Version 0.2.5.0
svn merge -r 15013:15295 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@15296 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/.gitignore b/.gitignore
index 5c2afd1..ce9b95f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -74,3 +74,6 @@
# Pub generated "packages" directories
packages
+
+# Vim temporary swap files.
+*.swp
diff --git a/client/dart.js b/client/dart.js
index c76e3fa..1c8b333 100644
--- a/client/dart.js
+++ b/client/dart.js
@@ -159,11 +159,21 @@
window.registerPort = function(name, port) {
var stringified = JSON.stringify(serialize(port));
- window.localStorage['dart-port:' + name] = stringified;
+ var attrName = 'dart-port:' + name;
+ document.documentElement.setAttribute(attrName, stringified);
+ // TODO(vsm): Phase out usage of localStorage. We're leaving it in
+ // temporarily for backwards compatibility.
+ window.localStorage[attrName] = stringified;
};
window.lookupPort = function(name) {
- var stringified = window.localStorage['dart-port:' + name];
+ var attrName = 'dart-port:' + name;
+ var stringified = document.documentElement.getAttribute(attrName);
+ // TODO(vsm): Phase out usage of localStorage. We're leaving it in
+ // temporarily for backwards compatibility.
+ if (!stringified) {
+ stringified = window.localStorage[attrName];
+ }
return deserialize(JSON.parse(stringified));
};
diff --git a/compiler/java/com/google/dart/compiler/UrlLibrarySource.java b/compiler/java/com/google/dart/compiler/UrlLibrarySource.java
index efc71d3..f5ec48c 100644
--- a/compiler/java/com/google/dart/compiler/UrlLibrarySource.java
+++ b/compiler/java/com/google/dart/compiler/UrlLibrarySource.java
@@ -70,6 +70,12 @@
try {
// Force the creation of an escaped relative URI to deal with spaces, etc.
URI uri = getUri().resolve(new URI(null, null, relPath, null, null)).normalize();
+ if (PackageLibraryManager.isPackageUri(uri)) {
+ URI fileUri = packageLibraryManager.resolveDartUri(uri);
+ if (fileUri != null) {
+ uri = fileUri;
+ }
+ }
return createDartSource(uri, relPath, this, packageLibraryManager);
} catch (Throwable e) {
return null;
diff --git a/compiler/java/com/google/dart/compiler/ast/DartDeclaration.java b/compiler/java/com/google/dart/compiler/ast/DartDeclaration.java
index 5080bb1..35f3013 100644
--- a/compiler/java/com/google/dart/compiler/ast/DartDeclaration.java
+++ b/compiler/java/com/google/dart/compiler/ast/DartDeclaration.java
@@ -10,7 +10,8 @@
* considered a part of the declaration, not an independent node. So the name is not visited when
* traversing the AST.
*/
-public abstract class DartDeclaration<N extends DartExpression> extends DartNodeWithMetadata {
+public abstract class DartDeclaration<N extends DartExpression> extends DartNodeWithMetadata
+ implements HasObsoleteMetadata {
private N name; // Not visited.
private DartComment dartDoc;
diff --git a/compiler/java/com/google/dart/compiler/ast/DartDirective.java b/compiler/java/com/google/dart/compiler/ast/DartDirective.java
index ad1a9ec..7c039c1 100644
--- a/compiler/java/com/google/dart/compiler/ast/DartDirective.java
+++ b/compiler/java/com/google/dart/compiler/ast/DartDirective.java
@@ -1,4 +1,4 @@
-// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// 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.
@@ -9,9 +9,19 @@
/**
* Base class for directives.
*/
-public abstract class DartDirective extends DartNodeWithMetadata {
+public abstract class DartDirective extends DartNodeWithMetadata implements HasObsoleteMetadata {
+ private DartObsoleteMetadata obsoleteMetadata = DartObsoleteMetadata.EMPTY;
+
@Override
public NodeElement getElement() {
throw new UnsupportedOperationException(getClass().getSimpleName());
}
+
+ public DartObsoleteMetadata getObsoleteMetadata() {
+ return obsoleteMetadata;
+ }
+
+ public void setObsoleteMetadata(DartObsoleteMetadata metadata) {
+ this.obsoleteMetadata = metadata;
+ }
}
diff --git a/compiler/java/com/google/dart/compiler/ast/DartStringLiteral.java b/compiler/java/com/google/dart/compiler/ast/DartStringLiteral.java
index 91c69d9..e2a83bf 100644
--- a/compiler/java/com/google/dart/compiler/ast/DartStringLiteral.java
+++ b/compiler/java/com/google/dart/compiler/ast/DartStringLiteral.java
@@ -5,6 +5,7 @@
package com.google.dart.compiler.ast;
import com.google.common.collect.ImmutableList;
+import com.google.dart.compiler.resolver.Element;
import java.util.List;
@@ -12,6 +13,8 @@
* Represents a Dart string literal value.
*/
public class DartStringLiteral extends DartLiteral {
+
+ private Element element;
public static DartStringLiteral get(String x) {
return new DartStringLiteral(x, null);
@@ -43,6 +46,16 @@
}
return parts;
}
+
+ @Override
+ public void setElement(Element element) {
+ this.element = element;
+ }
+
+ @Override
+ public Element getElement() {
+ return element;
+ }
@Override
public void visitChildren(ASTVisitor<?> visitor) {
diff --git a/compiler/java/com/google/dart/compiler/ast/HasObsoleteMetadata.java b/compiler/java/com/google/dart/compiler/ast/HasObsoleteMetadata.java
new file mode 100644
index 0000000..b1648aa
--- /dev/null
+++ b/compiler/java/com/google/dart/compiler/ast/HasObsoleteMetadata.java
@@ -0,0 +1,12 @@
+// 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.
+
+package com.google.dart.compiler.ast;
+
+public interface HasObsoleteMetadata {
+
+ DartObsoleteMetadata getObsoleteMetadata();
+
+ void setObsoleteMetadata(DartObsoleteMetadata metadata);
+}
diff --git a/compiler/java/com/google/dart/compiler/ast/LibraryUnit.java b/compiler/java/com/google/dart/compiler/ast/LibraryUnit.java
index d6e2a31..2bd491f 100644
--- a/compiler/java/com/google/dart/compiler/ast/LibraryUnit.java
+++ b/compiler/java/com/google/dart/compiler/ast/LibraryUnit.java
@@ -187,6 +187,14 @@
public void setSelfDartUnit(DartUnit unit) {
this.selfDartUnit = unit;
+ // set DartObsoleteMetadata for LibraryElement
+ if (unit != null) {
+ List<DartDirective> directives = unit.getDirectives();
+ if (!directives.isEmpty() && directives.get(0) instanceof DartLibraryDirective) {
+ DartLibraryDirective libraryDirective = (DartLibraryDirective) directives.get(0);
+ Elements.setLibraryMetadata(element, libraryDirective.getObsoleteMetadata());
+ }
+ }
}
/**
diff --git a/compiler/java/com/google/dart/compiler/parser/DartParser.java b/compiler/java/com/google/dart/compiler/parser/DartParser.java
index 7537e43..a79148c 100644
--- a/compiler/java/com/google/dart/compiler/parser/DartParser.java
+++ b/compiler/java/com/google/dart/compiler/parser/DartParser.java
@@ -96,6 +96,7 @@
import com.google.dart.compiler.ast.DartVariable;
import com.google.dart.compiler.ast.DartVariableStatement;
import com.google.dart.compiler.ast.DartWhileStatement;
+import com.google.dart.compiler.ast.HasObsoleteMetadata;
import com.google.dart.compiler.ast.ImportCombinator;
import com.google.dart.compiler.ast.ImportHideCombinator;
import com.google.dart.compiler.ast.ImportShowCombinator;
@@ -336,8 +337,7 @@
// TODO(scheglov) remove after http://code.google.com/p/dart/issues/detail?id=6318
if (!Elements.isCoreLibrarySource(source)
&& !Elements.isLibrarySource(source, "/isolate/isolate.dart")
- && !Elements.isLibrarySource(source, "crypto/crypto.dart")
- && !Elements.isDart2JsLibrarySource(source)) {
+ && !Elements.isLibrarySource(source, "crypto/crypto.dart")) {
reportError(position(), ParserErrorCode.DEPRECATED_INTERFACE);
}
node = done(parseClass());
@@ -385,19 +385,26 @@
* @param metadata the metadata to be associated with the node
*/
private void setMetadata(DartNodeWithMetadata node, List<DartAnnotation> annotations) {
+ if (node instanceof DartFieldDefinition) {
+ DartFieldDefinition fieldDefinition = (DartFieldDefinition) node;
+ List<DartField> fields = fieldDefinition.getFields();
+ for (DartField field : fields) {
+ setMetadata(field, annotations);
+ }
+ return;
+ }
if (annotations != null && !annotations.isEmpty()) {
node.setMetadata(annotations);
- if (node instanceof DartDeclaration<?>) {
+ if (node instanceof HasObsoleteMetadata) {
+ HasObsoleteMetadata declaration = (HasObsoleteMetadata) node;
for (int i = 0, size = annotations.size(); i < size; i++) {
DartAnnotation annotation = annotations.get(i);
DartExpression nameNode = annotation.getName();
if (nameNode instanceof DartIdentifier) {
String name = ((DartIdentifier) nameNode).getName();
if (name.equals("deprecated")) {
- DartDeclaration<?> declaration = (DartDeclaration<?>) node;
declaration.setObsoleteMetadata(declaration.getObsoleteMetadata().makeDeprecated());
} else if (name.equals("override")) {
- DartDeclaration<?> declaration = (DartDeclaration<?>) node;
declaration.setObsoleteMetadata(declaration.getObsoleteMetadata().makeOverride());
}
}
@@ -1319,8 +1326,7 @@
&& !Elements.isLibrarySource(source, "/math/math.dart")
&& !Elements.isLibrarySource(source, "/io/io_runtime.dart")
&& !Elements.isLibrarySource(source, "/crypto/crypto.dart")
- && !Elements.isLibrarySource(source, "/utf/utf.dart")
- && !Elements.isDart2JsLibrarySource(source)) {
+ && !Elements.isLibrarySource(source, "/utf/utf.dart")) {
reportError(position(), ParserErrorCode.DEPRECATED_ABSTRACT_METHOD);
}
}
@@ -3750,9 +3756,8 @@
constructor = doneWithoutConsuming(toPrefixedType(parts));
} else {
// Named constructor.
- DartIdentifier identifier = (DartIdentifier)part2.getIdentifier();
- constructor = doneWithoutConsuming(new DartPropertyAccess(doneWithoutConsuming(part1),
- identifier));
+ DartIdentifier identifier = (DartIdentifier) part2.getIdentifier();
+ constructor = doneWithoutConsuming(new DartPropertyAccess(part1, identifier));
}
break;
}
diff --git a/compiler/java/com/google/dart/compiler/resolver/Elements.java b/compiler/java/com/google/dart/compiler/resolver/Elements.java
index 5fadc57..b95d48c 100644
--- a/compiler/java/com/google/dart/compiler/resolver/Elements.java
+++ b/compiler/java/com/google/dart/compiler/resolver/Elements.java
@@ -87,6 +87,10 @@
return new LibraryElementImplementation(libraryUnit);
}
+ public static void setLibraryMetadata(LibraryElement element, DartObsoleteMetadata metadata) {
+ ((LibraryElementImplementation) element).setMetadata(metadata);
+ }
+
public static void addExportedElement(LibraryElement libraryElement, Element element) {
((LibraryElementImplementation) libraryElement).addExportedElements(element);
}
@@ -744,21 +748,6 @@
}
return false;
}
-
- /**
- * @return <code>true</code> if given {@link Source} represents library with given name.
- */
- public static boolean isDart2JsLibrarySource(Source source) {
- if (source instanceof DartSource) {
- DartSource dartSource = (DartSource) source;
- LibrarySource library = dartSource.getLibrary();
- if (library != null) {
- String libraryName = library.getName();
- return libraryName.contains("lib/compiler/implementation/");
- }
- }
- return false;
- }
/**
* @return <code>true</code> if given {@link Source} represents code library declaration or
diff --git a/compiler/java/com/google/dart/compiler/resolver/LibraryElementImplementation.java b/compiler/java/com/google/dart/compiler/resolver/LibraryElementImplementation.java
index 8059600..ea4d530 100644
--- a/compiler/java/com/google/dart/compiler/resolver/LibraryElementImplementation.java
+++ b/compiler/java/com/google/dart/compiler/resolver/LibraryElementImplementation.java
@@ -5,6 +5,7 @@
package com.google.dart.compiler.resolver;
import com.google.common.collect.Lists;
+import com.google.dart.compiler.ast.DartObsoleteMetadata;
import com.google.dart.compiler.ast.LibraryUnit;
import java.util.Collection;
@@ -17,6 +18,7 @@
private final List<Element> exportedElements = Lists.newArrayList();
private LibraryUnit libraryUnit;
private MethodElement entryPoint;
+ private DartObsoleteMetadata metadata;
public LibraryElementImplementation(LibraryUnit libraryUnit) {
// TODO(ngeoffray): What should we pass the super? Should a LibraryUnit be a node?
@@ -85,4 +87,13 @@
void addMethod(MethodElement method) {
scope.declareElement(method.getName(), method);
}
+
+ @Override
+ public DartObsoleteMetadata getMetadata() {
+ return metadata;
+ }
+
+ public void setMetadata(DartObsoleteMetadata metadata) {
+ this.metadata = metadata;
+ }
}
diff --git a/compiler/java/com/google/dart/compiler/resolver/ResolveVisitor.java b/compiler/java/com/google/dart/compiler/resolver/ResolveVisitor.java
index ad1da78..3068877 100644
--- a/compiler/java/com/google/dart/compiler/resolver/ResolveVisitor.java
+++ b/compiler/java/com/google/dart/compiler/resolver/ResolveVisitor.java
@@ -16,6 +16,7 @@
import com.google.dart.compiler.ast.DartThisExpression;
import com.google.dart.compiler.ast.DartTypeNode;
import com.google.dart.compiler.ast.DartTypeParameter;
+import com.google.dart.compiler.common.HasSourceInfo;
import com.google.dart.compiler.type.FunctionType;
import com.google.dart.compiler.type.Type;
import com.google.dart.compiler.type.Types;
@@ -143,11 +144,15 @@
node.setType(type);
Element element = type.getElement();
recordElement(node.getIdentifier(), element);
+ checkDeprecated(node, element);
+ return type;
+ }
+
+ protected final void checkDeprecated(HasSourceInfo nameNode, Element element) {
if (element != null && element.getMetadata().isDeprecated()) {
- getContext().onError(node.getIdentifier(), TypeErrorCode.DEPRECATED_ELEMENT,
+ getContext().onError(nameNode, TypeErrorCode.DEPRECATED_ELEMENT,
Elements.getDeprecatedElementTitle(element));
}
- return type;
}
protected <E extends Element> E recordElement(DartNode node, E element) {
diff --git a/compiler/java/com/google/dart/compiler/resolver/Resolver.java b/compiler/java/com/google/dart/compiler/resolver/Resolver.java
index 71d67b2..88b06e4 100644
--- a/compiler/java/com/google/dart/compiler/resolver/Resolver.java
+++ b/compiler/java/com/google/dart/compiler/resolver/Resolver.java
@@ -40,6 +40,7 @@
import com.google.dart.compiler.ast.DartGotoStatement;
import com.google.dart.compiler.ast.DartIdentifier;
import com.google.dart.compiler.ast.DartIfStatement;
+import com.google.dart.compiler.ast.DartImportDirective;
import com.google.dart.compiler.ast.DartInitializer;
import com.google.dart.compiler.ast.DartIntegerLiteral;
import com.google.dart.compiler.ast.DartInvocation;
@@ -76,6 +77,8 @@
import com.google.dart.compiler.ast.DartVariable;
import com.google.dart.compiler.ast.DartVariableStatement;
import com.google.dart.compiler.ast.DartWhileStatement;
+import com.google.dart.compiler.ast.LibraryImport;
+import com.google.dart.compiler.ast.LibraryUnit;
import com.google.dart.compiler.ast.Modifiers;
import com.google.dart.compiler.common.HasSourceInfo;
import com.google.dart.compiler.common.SourceInfo;
@@ -230,11 +233,33 @@
@Override
public Element visitUnit(DartUnit unit) {
+ List<DartImportDirective> importDirectives = Lists.newArrayList();
for (DartDirective directive : unit.getDirectives()) {
+ if (directive instanceof DartImportDirective) {
+ importDirectives.add((DartImportDirective) directive);
+ }
if (directive instanceof DartPartOfDirective) {
directive.accept(this);
}
}
+ // set LibraryElement for "import" directives
+ {
+ LibraryUnit library = unit.getLibrary();
+ if (library != null) {
+ Iterator<LibraryImport> importIterator = library.getImports().iterator();
+ Iterator<DartImportDirective> directiveIterator = importDirectives.iterator();
+ while (importIterator.hasNext() && directiveIterator.hasNext()) {
+ LibraryImport imp = importIterator.next();
+ DartImportDirective dir = directiveIterator.next();
+ DartStringLiteral uri = dir.getLibraryUri();
+ LibraryUnit impLibrary = imp.getLibrary();
+ if (uri != null && impLibrary != null) {
+ uri.setElement(impLibrary.getElement());
+ }
+ }
+ }
+ }
+ // visit top-level nodes
for (DartNode node : unit.getTopLevelNodes()) {
node.accept(this);
}
@@ -715,10 +740,19 @@
}
resolve(functionNode.getBody());
- if (Elements.isNonFactoryConstructor(member)
- && !(body instanceof DartNativeBlock)) {
+ if (Elements.isNonFactoryConstructor(member) && !(body instanceof DartNativeBlock)) {
resolveInitializers(node, initializedFields);
}
+
+ // only generative constructor can have initializers, so resolve them, but report error
+ if (!member.isConstructor() || member.getModifiers().isFactory()) {
+ for (DartInitializer initializer : node.getInitializers()) {
+ resolve(initializer);
+ if (initializer.getName() != null) {
+ onError(initializer, ResolverErrorCode.INITIALIZER_ONLY_IN_GENERATIVE_CONSTRUCTOR);
+ }
+ }
+ }
// resolve redirecting factory constructor
{
@@ -1253,6 +1287,20 @@
}
}
+ if (ElementKind.of(element) == ElementKind.FIELD) {
+ FieldElement fieldElement = (FieldElement) element;
+ if (fieldElement.getModifiers().isAbstractField()) {
+ if (fieldElement.getGetter() == null && ASTNodes.inGetterContext(x)) {
+ topLevelContext.onError(x, ResolverErrorCode.FIELD_DOES_NOT_HAVE_A_GETTER);
+ x.markResolutionAlreadyReportedThatTheMethodCouldNotBeFound();
+ }
+ if (fieldElement.getSetter() == null && ASTNodes.inSetterContext(x)) {
+ topLevelContext.onError(x, ResolverErrorCode.FIELD_DOES_NOT_HAVE_A_SETTER);
+ x.markResolutionAlreadyReportedThatTheMethodCouldNotBeFound();
+ }
+ }
+ }
+
// May be local variable declared in lexical scope, but its declaration is not visited yet.
if (getContext().getScope().isDeclaredButNotReachedVariable(name)) {
onError(x, ResolverErrorCode.USING_LOCAL_VARIABLE_BEFORE_DECLARATION, x);
@@ -1278,6 +1326,7 @@
// If we we haven't resolved the identifier, it will be normalized to
// this.<identifier>.
+ checkDeprecated(x, element);
return recordElement(x, element);
}
@@ -1319,19 +1368,9 @@
return typeProvider.getTypeType().getElement();
}
break;
+ case FUNCTION_TYPE_ALIAS:
case TYPE_VARIABLE:
- // Type variables are not legal in identifier expressions, but the type variable
- // may be hiding a class element.
- LibraryElement libraryElement = scope.getLibrary();
- Scope libraryScope = libraryElement.getScope();
- // dip again at the library level.
- element = libraryScope.findElement(libraryElement, name);
- if (element == null) {
- onError(x, ResolverErrorCode.TYPE_VARIABLE_NOT_ALLOWED_IN_IDENTIFIER);
- } else {
- return checkResolvedIdentifier(x, isQualifier, libraryScope, name, element);
- }
- break;
+ return typeProvider.getTypeType().getElement();
default:
break;
}
diff --git a/compiler/java/com/google/dart/compiler/resolver/ResolverErrorCode.java b/compiler/java/com/google/dart/compiler/resolver/ResolverErrorCode.java
index 550ea7e..f6d91c6 100644
--- a/compiler/java/com/google/dart/compiler/resolver/ResolverErrorCode.java
+++ b/compiler/java/com/google/dart/compiler/resolver/ResolverErrorCode.java
@@ -127,6 +127,7 @@
ILLEGAL_ACCESS_TO_PRIVATE_MEMBER("\"%s\" refers to \"%s\" which is in a different library"),
ILLEGAL_FIELD_ACCESS_FROM_STATIC("Illegal access of instance field %s from static scope"),
ILLEGAL_METHOD_ACCESS_FROM_STATIC("Illegal access of instance method %s from static scope"),
+ INITIALIZER_ONLY_IN_GENERATIVE_CONSTRUCTOR("Initializers are allowed only in non-redirecting generative constructors"),
INIT_FIELD_ONLY_IMMEDIATELY_SURROUNDING_CLASS(
"Only fields of immediately surrounding class can be initialized"),
INSTANCE_METHOD_FROM_INITIALIZER("Instance methods cannot be referenced from constructor initializer"),
diff --git a/compiler/java/com/google/dart/compiler/type/InterfaceType.java b/compiler/java/com/google/dart/compiler/type/InterfaceType.java
index 7a746c1..99b7c9d 100644
--- a/compiler/java/com/google/dart/compiler/type/InterfaceType.java
+++ b/compiler/java/com/google/dart/compiler/type/InterfaceType.java
@@ -35,6 +35,10 @@
void registerSubClass(ClassElement subClass);
void unregisterSubClass(ClassElement subClass);
+ /**
+ * @return the unique {@link Member} with given name, defined in one of the subtypes. May be
+ * <code>null</code> if not found or not unique.
+ */
Member lookupSubTypeMember(String name);
interface Member {
diff --git a/compiler/java/com/google/dart/compiler/type/InterfaceTypeImplementation.java b/compiler/java/com/google/dart/compiler/type/InterfaceTypeImplementation.java
index fac151a..52c63ce 100644
--- a/compiler/java/com/google/dart/compiler/type/InterfaceTypeImplementation.java
+++ b/compiler/java/com/google/dart/compiler/type/InterfaceTypeImplementation.java
@@ -233,21 +233,32 @@
@Override
public Member lookupSubTypeMember(String name) {
+ Member foundMember = null;
for (ClassElement subClass : subClasses.keySet()) {
+ // find one or more members in subClass elements
{
Element element = subClass.lookupLocalElement(name);
if (element != null) {
- return new MemberImplementation(this, element);
+ if (foundMember != null) {
+ return null;
+ }
+ foundMember = new MemberImplementation(this, element);
+ continue;
}
}
+ // try to find deeper
InterfaceType type = subClass.getType();
if (type != null) {
Member member = type.lookupSubTypeMember(name);
if (member != null) {
- return member;
+ if (foundMember != null) {
+ return null;
+ }
+ foundMember = member;
}
}
}
- return null;
+ // may be found
+ return foundMember;
}
}
diff --git a/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java b/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java
index 1ca3593..e6a6419 100644
--- a/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java
+++ b/compiler/java/com/google/dart/compiler/type/TypeAnalyzer.java
@@ -1860,7 +1860,7 @@
@Override
public Type visitFunctionExpression(DartFunctionExpression node) {
node.visitChildren(this);
- Type result = ((Element) node.getElement()).getType();
+ Type result = node.getElement().getType();
result.getClass(); // quick null check
return result;
}
diff --git a/compiler/javatests/com/google/dart/compiler/resolver/ResolverTest.java b/compiler/javatests/com/google/dart/compiler/resolver/ResolverTest.java
index 75dfde1..90d8486 100644
--- a/compiler/javatests/com/google/dart/compiler/resolver/ResolverTest.java
+++ b/compiler/javatests/com/google/dart/compiler/resolver/ResolverTest.java
@@ -823,8 +823,7 @@
" try {",
" 0.25 - f;",
" } catch(e) {}",
- "}"),
- ResolverErrorCode.CANNOT_USE_TYPE);
+ "}"));
}
public void test_classUsedAsExpression() {
@@ -841,11 +840,11 @@
"class A<B> {",
" var field = B;",
" f() {",
- " 0.25 - B;",
+ " process(x);",
" }",
- "}"),
- ResolverErrorCode.TYPE_VARIABLE_NOT_ALLOWED_IN_IDENTIFIER,
- ResolverErrorCode.TYPE_VARIABLE_NOT_ALLOWED_IN_IDENTIFIER);
+ "}",
+ "process(x) {}",
+ ""));
}
public void test_shadowType_withVariable() throws Exception {
@@ -1057,6 +1056,8 @@
" result = instance.setter3;",
" instance.setter3 = 1;",
"}"),
+ errEx(ResolverErrorCode.FIELD_DOES_NOT_HAVE_A_SETTER, 13, 3, 7),
+ errEx(ResolverErrorCode.FIELD_DOES_NOT_HAVE_A_GETTER, 14, 12, 7),
errEx(ResolverErrorCode.FIELD_DOES_NOT_HAVE_A_SETTER, 17, 5, 7),
errEx(ResolverErrorCode.FIELD_DOES_NOT_HAVE_A_GETTER, 18, 14, 7));
}
diff --git a/compiler/javatests/com/google/dart/compiler/type/TypeAnalyzerCompilerTest.java b/compiler/javatests/com/google/dart/compiler/type/TypeAnalyzerCompilerTest.java
index f1a8dcb..5f72504 100644
--- a/compiler/javatests/com/google/dart/compiler/type/TypeAnalyzerCompilerTest.java
+++ b/compiler/javatests/com/google/dart/compiler/type/TypeAnalyzerCompilerTest.java
@@ -3707,6 +3707,8 @@
"const deprecated = 0;",
"@deprecated",
"ttt() {}",
+ "@deprecated",
+ "get topLevelGet => 42;",
"class A {",
" var @deprecated fff;",
" @deprecated",
@@ -3716,6 +3718,7 @@
"}",
"method() {",
" ttt();",
+ " print(topLevelGet);",
" A a = new A();",
" a.fff = 0;",
" a.mmmm();",
@@ -3724,10 +3727,11 @@
"");
assertErrors(
libraryResult.getErrors(),
- errEx(TypeErrorCode.DEPRECATED_ELEMENT, 13, 3, 3),
- errEx(TypeErrorCode.DEPRECATED_ELEMENT, 15, 5, 3),
- errEx(TypeErrorCode.DEPRECATED_ELEMENT, 16, 5, 4),
- errEx(TypeErrorCode.DEPRECATED_ELEMENT, 17, 5, 1));
+ errEx(TypeErrorCode.DEPRECATED_ELEMENT, 16, 9, 11),
+ errEx(TypeErrorCode.DEPRECATED_ELEMENT, 15, 3, 3),
+ errEx(TypeErrorCode.DEPRECATED_ELEMENT, 18, 5, 3),
+ errEx(TypeErrorCode.DEPRECATED_ELEMENT, 19, 5, 4),
+ errEx(TypeErrorCode.DEPRECATED_ELEMENT, 20, 5, 1));
}
public void test_metadataComment_deprecated_2() throws Exception {
@@ -5351,6 +5355,32 @@
assertErrors(result.getErrors(), errEx(TypeErrorCode.CANNOT_BE_RESOLVED, 5, 5, 1));
}
+ public void test_field_unqualifiedAccess_read() throws Exception {
+ AnalyzeLibraryResult result = analyzeLibrary(
+ "// filler filler filler filler filler filler filler filler filler filler",
+ "class A {",
+ " set f(x) {}",
+ " run() {",
+ " var v = f;",
+ " }",
+ "}",
+ "");
+ assertErrors(result.getErrors(), errEx(ResolverErrorCode.FIELD_DOES_NOT_HAVE_A_GETTER, 5, 13, 1));
+ }
+
+ public void test_field_unqualifiedAccess_write() throws Exception {
+ AnalyzeLibraryResult result = analyzeLibrary(
+ "// filler filler filler filler filler filler filler filler filler filler",
+ "class A {",
+ " get f => 0;",
+ " run() {",
+ " f = 1;",
+ " }",
+ "}",
+ "");
+ assertErrors(result.getErrors(), errEx(ResolverErrorCode.FIELD_DOES_NOT_HAVE_A_SETTER, 5, 5, 1));
+ }
+
public void test_typeVariableScope_staticField() throws Exception {
AnalyzeLibraryResult result = analyzeLibrary(
"// filler filler filler filler filler filler filler filler filler filler",
@@ -5470,6 +5500,41 @@
}
/**
+ * We should resolve sub-type member only if there is only sub-type with such member.
+ * <p>
+ * http://code.google.com/p/dart/issues/detail?id=6776
+ */
+ public void test_trySubTypeMember_moreThanOneMember() throws Exception {
+ compilerConfiguration = new DefaultCompilerConfiguration(new CompilerOptions() {
+ @Override
+ public boolean typeChecksForInferredTypes() {
+ return true;
+ }
+ });
+ AnalyzeLibraryResult result = analyzeLibrary(
+ "// filler filler filler filler filler filler filler filler filler filler",
+ "class Event {}",
+ "class MouseEvent extends Event {",
+ " int clientX;",
+ "}",
+ "class ScreenEvent extends Event {",
+ " int clientX;",
+ "}",
+ "typedef Listener(Event event);",
+ "class Button {",
+ " addListener(Listener listener) {}",
+ "}",
+ "main() {",
+ " Button button = new Button();",
+ " button.addListener((event) {",
+ " event.clientX;",
+ " });",
+ "}",
+ "");
+ assertErrors(result.getErrors(), errEx(TypeErrorCode.NOT_A_MEMBER_OF_INFERRED, 16, 11, 7));
+ }
+
+ /**
* <p>
* http://code.google.com/p/dart/issues/detail?id=6491
*/
@@ -5625,4 +5690,20 @@
assertErrors(result.getErrors(),
errEx(ResolverErrorCode.NOT_GENERATIVE_SUPER_CONSTRUCTOR, 8, 9, 13));
}
+
+ /**
+ * <p>
+ * http://code.google.com/p/dart/issues/detail?id=6718
+ */
+ public void test_initializerInMethod() throws Exception {
+ AnalyzeLibraryResult result = analyzeLibrary(
+ "// filler filler filler filler filler filler filler filler filler filler",
+ "class A {",
+ " var x;",
+ " B() : x = (foo() { }) {}",
+ "}",
+ "");
+ assertErrors(result.getErrors(),
+ errEx(ResolverErrorCode.INITIALIZER_ONLY_IN_GENERATIVE_CONSTRUCTOR, 4, 9, 15));
+ }
}
diff --git a/dart.gyp b/dart.gyp
index 3ec8489..b76a758 100644
--- a/dart.gyp
+++ b/dart.gyp
@@ -13,6 +13,9 @@
'actions': []
},
{
+ # This is the target that is built on the VM build bots. It
+ # must depend on anything that is required by the VM test
+ # suites.
'target_name': 'runtime',
'type': 'none',
'dependencies': [
@@ -21,6 +24,7 @@
'runtime/dart-runtime.gyp:run_vm_tests',
'runtime/dart-runtime.gyp:process_test',
'runtime/dart-runtime.gyp:test_extension',
+ 'packages',
],
},
{
@@ -104,11 +108,15 @@
],
},
{
+ # This is the target that is built on the dart2js build bots.
+ # It must depend on anything that is required by the dart2js
+ # test suites.
'target_name': 'dart2js_bot',
'type': 'none',
'dependencies': [
'third_party/v8/src/d8.gyp:d8',
'create_sdk',
+ 'packages',
],
},
{
@@ -125,5 +133,12 @@
'samples/sample_extension/sample_extension.gyp:sample_extension',
],
},
+ {
+ 'target_name': 'packages',
+ 'type': 'none',
+ 'dependencies': [
+ 'pkg/pkg.gyp:pkg_packages',
+ ],
+ },
],
}
diff --git a/pkg/args/test/args_test.dart b/pkg/args/test/args_test.dart
index 10c68fe..728ff7d 100644
--- a/pkg/args/test/args_test.dart
+++ b/pkg/args/test/args_test.dart
@@ -6,8 +6,7 @@
import '../../../pkg/unittest/lib/unittest.dart';
-// TODO(rnystrom): Use "package:" URL here when test.dart can handle pub.
-import '../lib/args.dart';
+import 'package:args/args.dart';
main() {
group('ArgParser.addFlag()', () {
diff --git a/pkg/fixnum/lib/src/int32.dart b/pkg/fixnum/lib/src/int32.dart
index 80f5f3c..ac92a7e 100644
--- a/pkg/fixnum/lib/src/int32.dart
+++ b/pkg/fixnum/lib/src/int32.dart
@@ -142,7 +142,7 @@
// will be truncated.
int _convert(other) {
if (other == null) {
- throw new NullPointerException();
+ throw new ArgumentError(null);
} else if (other is intx) {
return other.toInt32()._i;
} else if (other is int) {
diff --git a/pkg/fixnum/lib/src/int64.dart b/pkg/fixnum/lib/src/int64.dart
index cefb2c0..3ef0bc0 100644
--- a/pkg/fixnum/lib/src/int64.dart
+++ b/pkg/fixnum/lib/src/int64.dart
@@ -242,7 +242,7 @@
int64 _promote(other) {
if (other == null) {
- throw new NullPointerException();
+ throw new ArgumentError(null);
} else if (other is intx) {
other = other.toInt64();
} else if (other is int) {
diff --git a/pkg/fixnum/test/int_32_test.dart b/pkg/fixnum/test/int_32_test.dart
index 7ea6591..e719fa6 100644
--- a/pkg/fixnum/test/int_32_test.dart
+++ b/pkg/fixnum/test/int_32_test.dart
@@ -132,26 +132,26 @@
try {
new int32.fromInt(17) < null;
- Expect.fail("x < null should throw NullPointerException");
- } on NullPointerException catch (e) {
+ Expect.fail("x < null should throw ArgumentError");
+ } on ArgumentError catch (e) {
}
try {
new int32.fromInt(17) <= null;
- Expect.fail("x <= null should throw NullPointerException");
- } on NullPointerException catch (e) {
+ Expect.fail("x <= null should throw ArgumentError");
+ } on ArgumentError catch (e) {
}
try {
new int32.fromInt(17) > null;
- Expect.fail("x > null should throw NullPointerException");
- } on NullPointerException catch (e) {
+ Expect.fail("x > null should throw ArgumentError");
+ } on ArgumentError catch (e) {
}
try {
new int32.fromInt(17) < null;
- Expect.fail("x >= null should throw NullPointerException");
- } on NullPointerException catch (e) {
+ Expect.fail("x >= null should throw ArgumentError");
+ } on ArgumentError catch (e) {
}
Expect.isFalse(new int32.fromInt(17) == null);
diff --git a/pkg/fixnum/test/int_64_test.dart b/pkg/fixnum/test/int_64_test.dart
index 65d47b3..f41f45c 100644
--- a/pkg/fixnum/test/int_64_test.dart
+++ b/pkg/fixnum/test/int_64_test.dart
@@ -145,26 +145,26 @@
try {
new int64.fromInt(17) < null;
- Expect.fail("x < null should throw NullPointerException");
- } on NullPointerException catch (e) {
+ Expect.fail("x < null should throw ArgumentError");
+ } on ArgumentError catch (e) {
}
try {
new int64.fromInt(17) <= null;
- Expect.fail("x <= null should throw NullPointerException");
- } on NullPointerException catch (e) {
+ Expect.fail("x <= null should throw ArgumentError");
+ } on ArgumentError catch (e) {
}
try {
new int64.fromInt(17) > null;
- Expect.fail("x > null should throw NullPointerException");
- } on NullPointerException catch (e) {
+ Expect.fail("x > null should throw ArgumentError");
+ } on ArgumentError catch (e) {
}
try {
new int64.fromInt(17) < null;
- Expect.fail("x >= null should throw NullPointerException");
- } on NullPointerException catch (e) {
+ Expect.fail("x >= null should throw ArgumentError");
+ } on ArgumentError catch (e) {
}
Expect.isFalse(new int64.fromInt(17) == null);
diff --git a/pkg/http/lib/http.dart b/pkg/http/lib/http.dart
index 4ee2c61..ee074f7 100644
--- a/pkg/http/lib/http.dart
+++ b/pkg/http/lib/http.dart
@@ -37,11 +37,11 @@
/// This package is designed to be composable. This makes it easy for external
/// libraries to work with one another to add behavior to it. Libraries wishing
/// to add behavior should create a subclass of [BaseClient] that wraps another
-/// [BaseClient] and adds the desired behavior:
+/// [Client] and adds the desired behavior:
///
/// class UserAgentClient extends http.BaseClient {
/// final String userAgent;
-/// final HttpClient _inner;
+/// final http.Client _inner;
///
/// UserAgentClient(this.userAgent, this._inner);
///
@@ -50,9 +50,6 @@
/// return _inner.send(request);
/// }
/// }
-///
-/// In turn, libraries using [Client] should take a [BaseClient] so that the
-/// decorated clients can be used transparently.
library http;
@@ -65,7 +62,6 @@
export 'src/base_client.dart';
export 'src/base_request.dart';
export 'src/base_response.dart';
-export 'src/curl_client.dart';
export 'src/client.dart';
export 'src/multipart_file.dart';
export 'src/multipart_request.dart';
diff --git a/pkg/http/lib/src/base_client.dart b/pkg/http/lib/src/base_client.dart
index 0b9c52d..1662f00 100644
--- a/pkg/http/lib/src/base_client.dart
+++ b/pkg/http/lib/src/base_client.dart
@@ -9,6 +9,7 @@
import 'dart:uri';
import 'base_request.dart';
+import 'client.dart';
import 'request.dart';
import 'response.dart';
import 'streamed_response.dart';
@@ -17,7 +18,7 @@
/// The abstract base class for an HTTP client. This is a mixin-style class;
/// subclasses only need to implement [send] and maybe [close], and then they
/// get various convenience methods for free.
-abstract class BaseClient {
+abstract class BaseClient implements Client {
/// Sends an HTTP HEAD request with the given headers to the given URL, which
/// can be a [Uri] or a [String].
///
diff --git a/pkg/http/lib/src/client.dart b/pkg/http/lib/src/client.dart
index bbee58d..d60df93 100644
--- a/pkg/http/lib/src/client.dart
+++ b/pkg/http/lib/src/client.dart
@@ -8,75 +8,89 @@
import 'base_client.dart';
import 'base_request.dart';
+import 'io_client.dart';
import 'streamed_response.dart';
import 'utils.dart';
-/// An HTTP client which takes care of maintaining persistent connections across
-/// multiple requests to the same server. If you only need to send a single
-/// request, it's usually easier to use [head], [get], [post],
+/// The interface for HTTP clients that take care of maintaining persistent
+/// connections across multiple requests to the same server. If you only need to
+/// send a single request, it's usually easier to use [head], [get], [post],
/// [put], or [delete] instead.
///
-/// When creating an HTTP client class with additional functionality, it's
-/// recommended that you subclass [BaseClient] and wrap another instance of
-/// [BaseClient] rather than subclassing [Client] directly. This allows all
-/// subclasses of [BaseClient] to be mutually composable.
-class Client extends BaseClient {
- /// The underlying `dart:io` HTTP client.
- HttpClient _inner;
+/// When creating an HTTP client class with additional functionality, you must
+/// extend [BaseClient] rather than [Client]. In most cases, you can wrap
+/// another instance of [Client] and add functionality on top of that. This
+/// allows all classes implementing [Client] to be mutually composable.
+abstract class Client {
+ /// Creates a new Client using the default implementation. This implementation
+ /// uses an underlying `dart:io` [HttpClient] to make requests.
+ factory Client() => new IOClient();
- /// Creates a new HTTP client.
- Client() : _inner = new HttpClient();
+ /// Sends an HTTP HEAD request with the given headers to the given URL, which
+ /// can be a [Uri] or a [String].
+ ///
+ /// For more fine-grained control over the request, use [send] instead.
+ Future<Response> head(url, {Map<String, String> headers});
+
+ /// Sends an HTTP GET request with the given headers to the given URL, which
+ /// can be a [Uri] or a [String].
+ ///
+ /// For more fine-grained control over the request, use [send] instead.
+ Future<Response> get(url, {Map<String, String> headers});
+
+ /// Sends an HTTP POST request with the given headers and fields to the given
+ /// URL, which can be a [Uri] or a [String]. If any fields are specified, the
+ /// content-type is automatically set to
+ /// `"application/x-www-form-urlencoded"`.
+ ///
+ /// For more fine-grained control over the request, use [send] instead.
+ Future<Response> post(url,
+ {Map<String, String> headers,
+ Map<String, String> fields});
+
+ /// Sends an HTTP PUT request with the given headers and fields to the given
+ /// URL, which can be a [Uri] or a [String]. If any fields are specified, the
+ /// content-type is automatically set to
+ /// `"application/x-www-form-urlencoded"`.
+ ///
+ /// For more fine-grained control over the request, use [send] instead.
+ Future<Response> put(url,
+ {Map<String, String> headers,
+ Map<String, String> fields});
+
+ /// Sends an HTTP DELETE request with the given headers to the given URL,
+ /// which can be a [Uri] or a [String].
+ ///
+ /// For more fine-grained control over the request, use [send] instead.
+ Future<Response> delete(url, {Map<String, String> headers});
+
+ /// Sends an HTTP GET request with the given headers to the given URL, which
+ /// can be a [Uri] or a [String], and returns a Future that completes to the
+ /// body of the response as a String.
+ ///
+ /// The Future will emit an [HttpException] if the response doesn't have a
+ /// success status code.
+ ///
+ /// For more fine-grained control over the request and response, use [send] or
+ /// [get] instead.
+ Future<String> read(url, {Map<String, String> headers});
+
+ /// Sends an HTTP GET request with the given headers to the given URL, which
+ /// can be a [Uri] or a [String], and returns a Future that completes to the
+ /// body of the response as a list of bytes.
+ ///
+ /// The Future will emit an [HttpException] if the response doesn't have a
+ /// success status code.
+ ///
+ /// For more fine-grained control over the request and response, use [send] or
+ /// [get] instead.
+ Future<Uint8List> readBytes(url, {Map<String, String> headers});
/// Sends an HTTP request and asynchronously returns the response.
- Future<StreamedResponse> send(BaseRequest request) {
- var stream = request.finalize();
+ Future<StreamedResponse> send(BaseRequest request);
- var completer = new Completer<StreamedResponse>();
- var connection = _inner.openUrl(request.method, request.url);
- connection.onError = (e) {
- async.then((_) {
- // TODO(nweiz): remove this when issue 4974 is fixed
- if (completer.future.isComplete) throw e;
-
- completer.completeException(e);
- });
- };
-
- connection.onRequest = (underlyingRequest) {
- underlyingRequest.contentLength = request.contentLength;
- underlyingRequest.persistentConnection = request.persistentConnection;
- request.headers.forEach((name, value) {
- underlyingRequest.headers.set(name, value);
- });
-
- if (stream.closed) {
- underlyingRequest.outputStream.close();
- } else {
- stream.pipe(underlyingRequest.outputStream);
- }
- };
-
- connection.onResponse = (response) {
- var headers = <String>{};
- response.headers.forEach((key, value) => headers[key] = value);
-
- completer.complete(new StreamedResponse(
- response.inputStream,
- response.statusCode,
- response.contentLength,
- headers: headers,
- isRedirect: response.isRedirect,
- persistentConnection: response.persistentConnection,
- reasonPhrase: response.reasonPhrase));
- };
-
- return completer.future;
- }
-
- /// Closes the client. This terminates all active connections. If a client
- /// remains unclosed, the Dart process may not terminate.
- void close() {
- if (_inner != null) _inner.shutdown();
- _inner = null;
- }
+ /// Closes the client and cleans up any resources associated with it. It's
+ /// important to close each client when it's done being used; failing to do so
+ /// can cause the Dart process to hang.
+ void close();
}
diff --git a/pkg/http/lib/src/io_client.dart b/pkg/http/lib/src/io_client.dart
new file mode 100644
index 0000000..995ff3b
--- /dev/null
+++ b/pkg/http/lib/src/io_client.dart
@@ -0,0 +1,74 @@
+// 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.
+
+library io_client;
+
+import 'dart:io';
+
+import 'base_client.dart';
+import 'base_request.dart';
+import 'streamed_response.dart';
+import 'utils.dart';
+
+/// A `dart:io`-based HTTP client. This is the default client.
+class IOClient extends BaseClient {
+ /// The underlying `dart:io` HTTP client.
+ HttpClient _inner;
+
+ /// Creates a new HTTP client.
+ IOClient() : _inner = new HttpClient();
+
+ /// Sends an HTTP request and asynchronously returns the response.
+ Future<StreamedResponse> send(BaseRequest request) {
+ var stream = request.finalize();
+
+ var completer = new Completer<StreamedResponse>();
+ var connection = _inner.openUrl(request.method, request.url);
+ connection.onError = (e) {
+ async.then((_) {
+ // TODO(nweiz): remove this when issue 4974 is fixed
+ if (completer.future.isComplete) throw e;
+
+ completer.completeException(e);
+ });
+ };
+
+ connection.onRequest = (underlyingRequest) {
+ underlyingRequest.contentLength = request.contentLength;
+ underlyingRequest.persistentConnection = request.persistentConnection;
+ request.headers.forEach((name, value) {
+ underlyingRequest.headers.set(name, value);
+ });
+
+ if (stream.closed) {
+ underlyingRequest.outputStream.close();
+ } else {
+ stream.pipe(underlyingRequest.outputStream);
+ }
+ };
+
+ connection.onResponse = (response) {
+ var headers = <String>{};
+ response.headers.forEach((key, value) => headers[key] = value);
+
+ completer.complete(new StreamedResponse(
+ response.inputStream,
+ response.statusCode,
+ response.contentLength,
+ headers: headers,
+ isRedirect: response.isRedirect,
+ persistentConnection: response.persistentConnection,
+ reasonPhrase: response.reasonPhrase));
+ };
+
+ return completer.future;
+ }
+
+ /// Closes the client. This terminates all active connections. If a client
+ /// remains unclosed, the Dart process may not terminate.
+ void close() {
+ if (_inner != null) _inner.shutdown();
+ _inner = null;
+ }
+}
diff --git a/pkg/http/lib/src/utils.dart b/pkg/http/lib/src/utils.dart
index 665ee1e..8431603 100644
--- a/pkg/http/lib/src/utils.dart
+++ b/pkg/http/lib/src/utils.dart
@@ -185,26 +185,3 @@
}
return nextElement(null);
}
-
-/// Creates a temporary directory and passes its path to [fn]. Once the [Future]
-/// returned by [fn] completes, the temporary directory and all its contents
-/// will be deleted.
-Future withTempDir(Future fn(String path)) {
- var tempDir;
- var future = new Directory('').createTemp().chain((dir) {
- tempDir = dir;
- return fn(tempDir.path);
- });
- future.onComplete((_) => tempDir.delete(recursive: true));
- return future;
-}
-
-/// Configures [future] so that its result (success or exception) is passed on
-/// to [completer].
-void chainToCompleter(Future future, Completer completer) {
- future.handleException((e) {
- completer.completeException(e);
- return true;
- });
- future.then(completer.complete);
-}
diff --git a/pkg/http/test/request_test.dart b/pkg/http/test/request_test.dart
index 5c2d98c..319abfb 100644
--- a/pkg/http/test/request_test.dart
+++ b/pkg/http/test/request_test.dart
@@ -13,23 +13,16 @@
void main() {
test('.send', () {
- print("This test is known to be flaky, please ignore "
- "(debug prints below added by sgjesse@)");
- print(".send test starting server...");
startServer();
- print(".send test server running");
var request = new http.Request('POST', serverUrl);
request.body = "hello";
var future = request.send().chain((response) {
- print(".send test response received");
expect(response.statusCode, equals(200));
return consumeInputStream(response.stream);
}).transform((bytes) => new String.fromCharCodes(bytes));
future.onComplete((_) {
- print(".send test stopping server...");
stopServer();
- print(".send test server stopped");
});
expect(future, completion(parse(equals({
@@ -41,7 +34,6 @@
},
'body': 'hello'
}))));
- print(".send test started");
});
group('#contentLength', () {
diff --git a/pkg/oauth2/lib/oauth2.dart b/pkg/oauth2/lib/oauth2.dart
new file mode 100644
index 0000000..a7e9307
--- /dev/null
+++ b/pkg/oauth2/lib/oauth2.dart
@@ -0,0 +1,109 @@
+// 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.
+
+/// A client library for authenticating with a remote service via OAuth2 on
+/// behalf of a user, and making authorized HTTP requests with the user's OAuth2
+/// credentials.
+///
+/// OAuth2 allows a client (the program using this library) to access and
+/// manipulate a resource that's owned by a resource owner (the end user) and
+/// lives on a remote server. The client directs the resource owner to an
+/// authorization server (usually but not always the same as the server that
+/// hosts the resource), where the resource owner tells the authorization server
+/// to give the client an access token. This token serves as proof that the
+/// client has permission to access resources on behalf of the resource owner.
+///
+/// OAuth2 provides several different methods for the client to obtain
+/// authorization. At the time of writing, this library only supports the
+/// [AuthorizationCodeGrant] method, but further methods may be added in the
+/// future. The following example uses this method to authenticate, and assumes
+/// that the library is being used by a server-side application.
+///
+/// import 'dart:io'
+/// import 'dart:uri'
+/// import 'package:oauth2/oauth2.dart' as oauth2;
+///
+/// // These URLs are endpoints that are provided by the authorization
+/// // server. They're usually included in the server's documentation of its
+/// // OAuth2 API.
+/// final authorizationEndpoint =
+/// new Uri.fromString("http://example.com/oauth2/authorization");
+/// final tokenEndpoint =
+/// new Uri.fromString("http://example.com/oauth2/token");
+///
+/// // The authorization server will issue each client a separate client
+/// // identifier and secret, which allows the server to tell which client
+/// // is accessing it. Some servers may also have an anonymous
+/// // identifier/secret pair that any client may use.
+/// //
+/// // Note that clients whose source code or binary executable is readily
+/// // available may not be able to make sure the client secret is kept a
+/// // secret. This is fine; OAuth2 servers generally won't rely on knowing
+/// // with certainty that a client is who it claims to be.
+/// final identifier = "my client identifier";
+/// final secret = "my client secret";
+///
+/// // This is a URL on your application's server. The authorization server
+/// // will redirect the resource owner here once they've authorized the
+/// // client. The redirection will include the authorization code in the
+/// // query parameters.
+/// final redirectUrl = new Uri.fromString(
+/// "http://my-site.com/oauth2-redirect");
+///
+/// var credentialsFile = new File("~/.myapp/credentials.json");
+/// return credentialsFile.exists().chain((exists) {
+/// // If the OAuth2 credentials have already been saved from a previous
+/// // run, we just want to reload them.
+/// if (exists) {
+/// return credentialsFile.readAsText().transform((json) {
+/// var credentials = new oauth2.Credentials.fromJson(json);
+/// return new oauth2.Client(identifier, secret, credentials);
+/// });
+/// }
+///
+/// // If we don't have OAuth2 credentials yet, we need to get the
+/// // resource owner to authorize us. We're assuming here that we're a
+/// // command-line application.
+/// var grant = new oauth2.AuthorizationCodeGrant(
+/// identifier, secret, authorizationEndpoint, tokenEndpoint);
+///
+/// // Redirect the resource owner to the authorization URL. This will be
+/// // a URL on the authorization server (authorizationEndpoint with some
+/// // additional query parameters). Once the resource owner has
+/// // authorized, they'll be redirected to `redirectUrl` with an
+/// // authorization code.
+/// //
+/// // `redirect` is an imaginary function that redirects the resource
+/// // owner's browser.
+/// return redirect(grant.getAuthorizationUrl(redirectUrl)).chain((_) {
+/// // Another imaginary function that listens for a request to
+/// // `redirectUrl`.
+/// return listen(redirectUrl);
+/// }).transform((request) {
+/// // Once the user is redirected to `redirectUrl`, pass the query
+/// // parameters to the AuthorizationCodeGrant. It will validate them
+/// // and extract the authorization code to create a new Client.
+/// return grant.handleAuthorizationResponse(request.queryParameters);
+/// })
+/// }).chain((client) {
+/// // Once you have a Client, you can use it just like any other HTTP
+/// // client.
+/// return client.read("http://example.com/protected-resources.txt")
+/// .transform((result) {
+/// // Once we're done with the client, save the credentials file. This
+/// // ensures that if the credentials were automatically refreshed
+/// // while using the client, the new credentials are available for the
+/// // next run of the program.
+/// return credentialsFile.open(FileMode.WRITE).chain((file) {
+/// return file.writeString(client.credentials.toJson());
+/// }).chain((file) => file.close()).transform((_) => result);
+/// });
+/// }).then(print);
+library oauth2;
+
+export 'src/authorization_code_grant.dart';
+export 'src/client.dart';
+export 'src/credentials.dart';
+export 'src/authorization_exception.dart';
+export 'src/expiration_exception.dart';
diff --git a/pkg/oauth2/lib/src/authorization_code_grant.dart b/pkg/oauth2/lib/src/authorization_code_grant.dart
new file mode 100644
index 0000000..dcb36d06
--- /dev/null
+++ b/pkg/oauth2/lib/src/authorization_code_grant.dart
@@ -0,0 +1,258 @@
+// 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.
+
+library authorization_code_grant;
+
+import 'dart:uri';
+
+// TODO(nweiz): This should be a "package:" import. See issue 6745.
+import '../../../http/lib/http.dart' as http;
+
+import 'client.dart';
+import 'authorization_exception.dart';
+import 'handle_access_token_response.dart';
+import 'utils.dart';
+
+/// A class for obtaining credentials via an [authorization code grant][]. This
+/// method of authorization involves sending the resource owner to the
+/// authorization server where they will authorize the client. They're then
+/// redirected back to your server, along with an authorization code. This is
+/// used to obtain [Credentials] and create a fully-authorized [Client].
+///
+/// To use this class, you must first call [getAuthorizationUrl] to get the URL
+/// to which to redirect the resource owner. Then once they've been redirected
+/// back to your application, call [handleAuthorizationResponse] or
+/// [handleAuthorizationCode] to process the authorization server's response and
+/// construct a [Client].
+///
+/// [authorization code grant]: http://tools.ietf.org/html/draft-ietf-oauth-v2-31#section-4.1
+class AuthorizationCodeGrant {
+ /// An enum value for [_state] indicating that [getAuthorizationUrl] has not
+ /// yet been called for this grant.
+ static const _INITIAL_STATE = 0;
+
+ // An enum value for [_state] indicating that [getAuthorizationUrl] has been
+ // called but neither [handleAuthorizationResponse] nor
+ // [handleAuthorizationCode] has been called.
+ static const _AWAITING_RESPONSE_STATE = 1;
+
+ // An enum value for [_state] indicating that [getAuthorizationUrl] and either
+ // [handleAuthorizationResponse] or [handleAuthorizationCode] have been
+ // called.
+ static const _FINISHED_STATE = 2;
+
+ /// The client identifier for this client. The authorization server will issue
+ /// each client a separate client identifier and secret, which allows the
+ /// server to tell which client is accessing it. Some servers may also have an
+ /// anonymous identifier/secret pair that any client may use.
+ ///
+ /// This is usually global to the program using this library.
+ final String identifier;
+
+ /// The client secret for this client. The authorization server will issue
+ /// each client a separate client identifier and secret, which allows the
+ /// server to tell which client is accessing it. Some servers may also have an
+ /// anonymous identifier/secret pair that any client may use.
+ ///
+ /// This is usually global to the program using this library.
+ ///
+ /// Note that clients whose source code or binary executable is readily
+ /// available may not be able to make sure the client secret is kept a secret.
+ /// This is fine; OAuth2 servers generally won't rely on knowing with
+ /// certainty that a client is who it claims to be.
+ final String secret;
+
+ /// A URL provided by the authorization server that serves as the base for the
+ /// URL that the resource owner will be redirected to to authorize this
+ /// client. This will usually be listed in the authorization server's
+ /// OAuth2 API documentation.
+ final Uri authorizationEndpoint;
+
+ /// A URL provided by the authorization server that this library uses to
+ /// obtain long-lasting credentials. This will usually be listed in the
+ /// authorization server's OAuth2 API documentation.
+ final Uri tokenEndpoint;
+
+ /// The HTTP client used to make HTTP requests.
+ http.Client _httpClient;
+
+ /// The URL to which the resource owner will be redirected after they
+ /// authorize this client with the authorization server.
+ Uri _redirectEndpoint;
+
+ /// The scopes that the client is requesting access to.
+ List<String> _scopes;
+
+ /// An opaque string that users of this library may specify that will be
+ /// included in the response query parameters.
+ String _stateString;
+
+ /// The current state of the grant object. One of [_INITIAL_STATE],
+ /// [_AWAITING_RESPONSE_STATE], or [_FINISHED_STATE].
+ int _state = _INITIAL_STATE;
+
+ /// Creates a new grant.
+ ///
+ /// [httpClient] is used for all HTTP requests made by this grant, as well as
+ /// those of the [Client] is constructs.
+ AuthorizationCodeGrant(
+ this.identifier,
+ this.secret,
+ this.authorizationEndpoint,
+ this.tokenEndpoint,
+ {http.Client httpClient})
+ : _httpClient = httpClient == null ? new http.Client() : httpClient;
+
+ /// Returns the URL to which the resource owner should be redirected to
+ /// authorize this client. The resource owner will then be redirected to
+ /// [redirect], which should point to a server controlled by the client. This
+ /// redirect will have additional query parameters that should be passed to
+ /// [handleAuthorizationResponse].
+ ///
+ /// The specific permissions being requested from the authorization server may
+ /// be specified via [scopes]. The scope strings are specific to the
+ /// authorization server and may be found in its documentation. Note that you
+ /// may not be granted access to every scope you request; you may check the
+ /// [Credentials.scopes] field of [Client.credentials] to see which scopes you
+ /// were granted.
+ ///
+ /// An opaque [state] string may also be passed that will be present in the
+ /// query parameters provided to the redirect URL.
+ ///
+ /// It is a [StateError] to call this more than once.
+ Uri getAuthorizationUrl(Uri redirect,
+ {List<String> scopes: const <String>[], String state}) {
+ if (_state != _INITIAL_STATE) {
+ throw new StateError('The authorization URL has already been generated.');
+ }
+ _state = _AWAITING_RESPONSE_STATE;
+
+ this._redirectEndpoint = redirect;
+ this._scopes = scopes;
+ this._stateString = state;
+ var parameters = {
+ "response_type": "code",
+ "client_id": this.identifier,
+ "redirect_uri": redirect.toString()
+ };
+
+ if (state != null) parameters['state'] = state;
+ if (!scopes.isEmpty) parameters['scope'] = Strings.join(scopes, ' ');
+
+ return addQueryParameters(this.authorizationEndpoint, parameters);
+ }
+
+ /// Processes the query parameters added to a redirect from the authorization
+ /// server. Note that this "response" is not an HTTP response, but rather the
+ /// data passed to a server controlled by the client as query parameters on
+ /// the redirect URL.
+ ///
+ /// It is a [StateError] to call this more than once, to call it before
+ /// [getAuthorizationUrl] is called, or to call it after
+ /// [handleAuthorizationCode] is called.
+ ///
+ /// Throws [FormatError] if [parameters] is invalid according to the OAuth2
+ /// spec or if the authorization server otherwise provides invalid responses.
+ /// If `state` was passed to [getAuthorizationUrl], this will throw a
+ /// [FormatError] if the `state` parameter doesn't match the original value.
+ ///
+ /// Throws [AuthorizationException] if the authorization fails.
+ Future<Client> handleAuthorizationResponse(Map<String, String> parameters) {
+ return async.chain((_) {
+ if (_state == _INITIAL_STATE) {
+ throw new StateError(
+ 'The authorization URL has not yet been generated.');
+ } else if (_state == _FINISHED_STATE) {
+ throw new StateError(
+ 'The authorization code has already been received.');
+ }
+ _state = _FINISHED_STATE;
+
+ if (_stateString != null) {
+ if (!parameters.containsKey('state')) {
+ throw new FormatException('Invalid OAuth response for '
+ '"$authorizationEndpoint": parameter "state" expected to be '
+ '"$_stateString", was missing.');
+ } else if (parameters['state'] != _stateString) {
+ throw new FormatException('Invalid OAuth response for '
+ '"$authorizationEndpoint": parameter "state" expected to be '
+ '"$_stateString", was "${parameters['state']}".');
+ }
+ }
+
+ if (parameters.containsKey('error')) {
+ var description = parameters['error_description'];
+ var uriString = parameters['error_uri'];
+ var uri = uriString == null ? null : new Uri.fromString(uriString);
+ throw new AuthorizationException(parameters['error'], description, uri);
+ } else if (!parameters.containsKey('code')) {
+ throw new FormatException('Invalid OAuth response for '
+ '"$authorizationEndpoint": did not contain required parameter '
+ '"code".');
+ }
+
+ return _handleAuthorizationCode(parameters['code']);
+ });
+ }
+
+ /// Processes an authorization code directly. Usually
+ /// [handleAuthorizationResponse] is preferable to this method, since it
+ /// validates all of the query parameters. However, some authorization servers
+ /// allow the user to copy and paste an authorization code into a command-line
+ /// application, in which case this method must be used.
+ ///
+ /// It is a [StateError] to call this more than once, to call it before
+ /// [getAuthorizationUrl] is called, or to call it after
+ /// [handleAuthorizationCode] is called.
+ ///
+ /// Throws [FormatError] if the authorization server provides invalid
+ /// responses while retrieving credentials.
+ ///
+ /// Throws [AuthorizationException] if the authorization fails.
+ Future<Client> handleAuthorizationCode(String authorizationCode) {
+ return async.chain((_) {
+ if (_state == _INITIAL_STATE) {
+ throw new StateError(
+ 'The authorization URL has not yet been generated.');
+ } else if (_state == _FINISHED_STATE) {
+ throw new StateError(
+ 'The authorization code has already been received.');
+ }
+ _state = _FINISHED_STATE;
+
+ return _handleAuthorizationCode(authorizationCode);
+ });
+ }
+
+ /// This works just like [handleAuthorizationCode], except it doesn't validate
+ /// the state beforehand.
+ Future<Client> _handleAuthorizationCode(String authorizationCode) {
+ var startTime = new Date.now();
+ return _httpClient.post(this.tokenEndpoint, fields: {
+ "grant_type": "authorization_code",
+ "code": authorizationCode,
+ "redirect_uri": this._redirectEndpoint.toString(),
+ // TODO(nweiz): the spec recommends that HTTP basic auth be used in
+ // preference to form parameters, but Google doesn't support that. Should
+ // it be configurable?
+ "client_id": this.identifier,
+ "client_secret": this.secret
+ }).transform((response) {
+ var credentials = handleAccessTokenResponse(
+ response, tokenEndpoint, startTime, _scopes);
+ return new Client(
+ this.identifier, this.secret, credentials, httpClient: _httpClient);
+ });
+ }
+
+ /// Closes the grant and frees its resources.
+ ///
+ /// This will close the underlying HTTP client, which is shared by the
+ /// [Client] created by this grant, so it's not safe to close the grant and
+ /// continue using the client.
+ void close() {
+ if (_httpClient != null) _httpClient.close();
+ _httpClient = null;
+ }
+}
diff --git a/pkg/oauth2/lib/src/authorization_exception.dart b/pkg/oauth2/lib/src/authorization_exception.dart
new file mode 100644
index 0000000..1062aa9
--- /dev/null
+++ b/pkg/oauth2/lib/src/authorization_exception.dart
@@ -0,0 +1,37 @@
+// 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.
+
+library authorization_exception;
+
+import 'dart:io';
+import 'dart:uri';
+
+/// An exception raised when OAuth2 authorization fails.
+class AuthorizationException implements Exception {
+ /// The name of the error. Possible names are enumerated in [the spec][].
+ ///
+ /// [the spec]: http://tools.ietf.org/html/draft-ietf-oauth-v2-31#section-5.2
+ final String error;
+
+ /// The description of the error, provided by the server. Defaults to null.
+ final String description;
+
+ /// A URI for a page that describes the error in more detail, provided by the
+ /// server. Defaults to null.
+ final Uri uri;
+
+ /// Creates an AuthorizationException.
+ AuthorizationException(this.error, this.description, this.uri);
+
+ /// Provides a string description of the AuthorizationException.
+ String toString() {
+ var header = 'OAuth authorization error ($error)';
+ if (description != null) {
+ header = '$header: $description';
+ } else if (uri != null) {
+ header = '$header: $uri';
+ }
+ return '$header.';
+ }
+}
diff --git a/pkg/oauth2/lib/src/client.dart b/pkg/oauth2/lib/src/client.dart
new file mode 100644
index 0000000..7322afa
--- /dev/null
+++ b/pkg/oauth2/lib/src/client.dart
@@ -0,0 +1,124 @@
+// 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.
+
+library client;
+
+import 'dart:uri';
+
+import '../../../http/lib/http.dart' as http;
+
+import 'credentials.dart';
+import 'expiration_exception.dart';
+import 'utils.dart';
+
+// TODO(nweiz): Add an onCredentialsRefreshed event once we have some event
+// infrastructure.
+/// An OAuth2 client. This acts as a drop-in replacement for an [http.Client],
+/// while sending OAuth2 authorization credentials along with each request.
+///
+/// The client also automatically refreshes its credentials if possible. When it
+/// makes a request, if its credentials are expired, it will first refresh them.
+/// This means that any request may throw an [AuthorizationException] if the
+/// refresh is not authorized for some reason, a [FormatException] if the
+/// authorization server provides ill-formatted responses, or an
+/// [ExpirationException] if the credentials are expired and can't be refreshed.
+///
+/// Currently this client doesn't attempt to identify errors from the resource
+/// server that are caused by authentication failure. However, it may throw
+/// [AuthorizationException]s for such errors in the future.
+///
+/// If you already have a set of [Credentials], you can construct a [Client]
+/// directly. However, in order to first obtain the credentials, you must
+/// authorize. At the time of writing, the only authorization method this
+/// library supports is [AuthorizationCodeGrant].
+class Client extends http.BaseClient {
+ /// The client identifier for this client. The authorization server will issue
+ /// each client a separate client identifier and secret, which allows the
+ /// server to tell which client is accessing it. Some servers may also have an
+ /// anonymous identifier/secret pair that any client may use.
+ ///
+ /// This is usually global to the program using this library.
+ final String identifier;
+
+ /// The client secret for this client. The authorization server will issue
+ /// each client a separate client identifier and secret, which allows the
+ /// server to tell which client is accessing it. Some servers may also have an
+ /// anonymous identifier/secret pair that any client may use.
+ ///
+ /// This is usually global to the program using this library.
+ ///
+ /// Note that clients whose source code or binary executable is readily
+ /// available may not be able to make sure the client secret is kept a secret.
+ /// This is fine; OAuth2 servers generally won't rely on knowing with
+ /// certainty that a client is who it claims to be.
+ final String secret;
+
+ /// The credentials this client uses to prove to the resource server that it's
+ /// authorized. This may change from request to request as the credentials
+ /// expire and the client refreshes them automatically.
+ Credentials get credentials => _credentials;
+ Credentials _credentials;
+
+ /// The underlying HTTP client.
+ http.Client _httpClient;
+
+ /// Creates a new client from a pre-existing set of credentials. When
+ /// authorizing a client for the first time, you should use
+ /// [AuthorizationCodeGrant] instead of constructing a [Client] directly.
+ ///
+ /// [httpClient] is the underlying client that this forwards requests to after
+ /// adding authorization credentials to them.
+ Client(
+ this.identifier,
+ this.secret,
+ this._credentials,
+ {http.Client httpClient})
+ : _httpClient = httpClient == null ? new http.Client() : httpClient;
+
+ /// Sends an HTTP request with OAuth2 authorization credentials attached. This
+ /// will also automatically refresh this client's [Credentials] before sending
+ /// the request if necessary.
+ Future<http.StreamedResponse> send(http.BaseRequest request) {
+ return async.chain((_) {
+ if (!credentials.isExpired) return new Future.immediate(null);
+ if (!credentials.canRefresh) throw new ExpirationException(credentials);
+ return refreshCredentials();
+ }).chain((_) {
+ request.headers['authorization'] = "Bearer ${credentials.accessToken}";
+ return _httpClient.send(request);
+ });
+ // TODO(nweiz): parse 401 errors that are caused by OAuth errors here.
+ }
+
+ /// Explicitly refreshes this client's credentials. Returns this client.
+ ///
+ /// This will throw a [StateError] if the [Credentials] can't be refreshed, an
+ /// [AuthorizationException] if refreshing the credentials fails, or a
+ /// [FormatError] if the authorization server returns invalid responses.
+ ///
+ /// You may request different scopes than the default by passing in
+ /// [newScopes]. These must be a subset of the scopes in the
+ /// [Credentials.scopes] field of [Client.credentials].
+ Future<Client> refreshCredentials([List<String> newScopes]) {
+ return async.chain((_) {
+ if (!credentials.canRefresh) {
+ var prefix = "OAuth credentials";
+ if (credentials.isExpired) prefix = "$prefix have expired and";
+ throw new StateError("$prefix can't be refreshed.");
+ }
+
+ return credentials.refresh(identifier, secret,
+ newScopes: newScopes, httpClient: _httpClient);
+ }).transform((credentials) {
+ _credentials = credentials;
+ return this;
+ });
+ }
+
+ /// Closes this client and its underlying HTTP client.
+ void close() {
+ if (_httpClient != null) _httpClient.close();
+ _httpClient = null;
+ }
+}
diff --git a/pkg/oauth2/lib/src/credentials.dart b/pkg/oauth2/lib/src/credentials.dart
new file mode 100644
index 0000000..89af777
--- /dev/null
+++ b/pkg/oauth2/lib/src/credentials.dart
@@ -0,0 +1,191 @@
+// 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.
+
+library credentials;
+
+import 'dart:json';
+import 'dart:uri';
+
+import '../../../http/lib/http.dart' as http;
+import 'handle_access_token_response.dart';
+import 'utils.dart';
+
+/// Credentials that prove that a client is allowed to access a resource on the
+/// resource owner's behalf. These credentials are long-lasting and can be
+/// safely persisted across multiple runs of the program.
+///
+/// Many authorization servers will attach an expiration date to a set of
+/// credentials, along with a token that can be used to refresh the credentials
+/// once they've expired. The [Client] will automatically refresh its
+/// credentials when necessary. It's also possible to explicitly refresh them
+/// via [Client.refreshCredentials] or [Credentials.refresh].
+///
+/// Note that a given set of credentials can only be refreshed once, so be sure
+/// to save the refreshed credentials for future use.
+class Credentials {
+ /// The token that is sent to the resource server to prove the authorization
+ /// of a client.
+ final String accessToken;
+
+ /// The token that is sent to the authorization server to refresh the
+ /// credentials. This is optional.
+ final String refreshToken;
+
+ /// The URL of the authorization server endpoint that's used to refresh the
+ /// credentials. This is optional.
+ final Uri tokenEndpoint;
+
+ /// The specific permissions being requested from the authorization server.
+ /// The scope strings are specific to the authorization server and may be
+ /// found in its documentation.
+ final List<String> scopes;
+
+ /// The date at which these credentials will expire. This is likely to be a
+ /// few seconds earlier than the server's idea of the expiration date.
+ final Date expiration;
+
+ /// Whether or not these credentials have expired. Note that it's possible the
+ /// credentials will expire shortly after this is called. However, since the
+ /// client's expiration date is kept a few seconds earlier than the server's,
+ /// there should be enough leeway to rely on this.
+ bool get isExpired => expiration != null && new Date.now() > expiration;
+
+ /// Whether it's possible to refresh these credentials.
+ bool get canRefresh => refreshToken != null && tokenEndpoint != null;
+
+ /// Creates a new set of credentials.
+ ///
+ /// This class is usually not constructed directly; rather, it's accessed via
+ /// [Client.credentials] after a [Client] is created by
+ /// [AuthorizationCodeGrant]. Alternately, it may be loaded from a serialized
+ /// form via [Credentials.fromJson].
+ Credentials(
+ this.accessToken,
+ [this.refreshToken,
+ this.tokenEndpoint,
+ this.scopes,
+ this.expiration]);
+
+ /// Loads a set of credentials from a JSON-serialized form. Throws
+ /// [FormatException] if the JSON is incorrectly formatted.
+ factory Credentials.fromJson(String json) {
+ void validate(bool condition, String message) {
+ if (condition) return;
+ throw new FormatException(
+ "Failed to load credentials: $message.\n\n$json");
+ }
+
+ var parsed;
+ try {
+ parsed = JSON.parse(json);
+ } catch (e) {
+ // TODO(nweiz): narrow this catch clause once issue 6775 is fixed.
+ validate(false, 'invalid JSON');
+ }
+
+ validate(parsed is Map, 'was not a JSON map');
+ validate(parsed.containsKey('accessToken'),
+ 'did not contain required field "accessToken"');
+ validate(parsed['accessToken'] is String,
+ 'required field "accessToken" was not a string, was '
+ '${parsed["accessToken"]}');
+
+
+ for (var stringField in ['refreshToken', 'tokenEndpoint']) {
+ var value = parsed[stringField];
+ validate(value == null || value is String,
+ 'field "$stringField" was not a string, was "$value"');
+ }
+
+ var scopes = parsed['scopes'];
+ validate(scopes == null || scopes is List,
+ 'field "scopes" was not a list, was "$scopes"');
+
+ var tokenEndpoint = parsed['tokenEndpoint'];
+ if (tokenEndpoint != null) {
+ tokenEndpoint = new Uri.fromString(tokenEndpoint);
+ }
+ var expiration = parsed['expiration'];
+ if (expiration != null) {
+ validate(expiration is int,
+ 'field "expiration" was not an int, was "$expiration"');
+ expiration = new Date.fromMillisecondsSinceEpoch(expiration);
+ }
+
+ return new Credentials(
+ parsed['accessToken'],
+ parsed['refreshToken'],
+ tokenEndpoint,
+ scopes,
+ expiration);
+ }
+
+ /// Serializes a set of credentials to JSON. Nothing is guaranteed about the
+ /// output except that it's valid JSON and compatible with
+ /// [Credentials.toJson].
+ String toJson() => JSON.stringify({
+ 'accessToken': accessToken,
+ 'refreshToken': refreshToken,
+ 'tokenEndpoint': tokenEndpoint == null ? null : tokenEndpoint.toString(),
+ 'scopes': scopes,
+ 'expiration': expiration == null ? null : expiration.millisecondsSinceEpoch
+ });
+
+ /// Returns a new set of refreshed credentials. See [Client.identifier] and
+ /// [Client.secret] for explanations of those parameters.
+ ///
+ /// You may request different scopes than the default by passing in
+ /// [newScopes]. These must be a subset of [scopes].
+ ///
+ /// This will throw a [StateError] if these credentials can't be refreshed, an
+ /// [AuthorizationException] if refreshing the credentials fails, or a
+ /// [FormatError] if the authorization server returns invalid responses.
+ Future<Credentials> refresh(
+ String identifier,
+ String secret,
+ {List<String> newScopes,
+ http.Client httpClient}) {
+ var scopes = this.scopes;
+ if (newScopes != null) scopes = newScopes;
+ if (scopes == null) scopes = <String>[];
+ if (httpClient == null) httpClient = new http.Client();
+
+ var startTime = new Date.now();
+ return async.chain((_) {
+ if (refreshToken == null) {
+ throw new StateError("Can't refresh credentials without a refresh "
+ "token.");
+ } else if (tokenEndpoint == null) {
+ throw new StateError("Can't refresh credentials without a token "
+ "endpoint.");
+ }
+
+ var fields = {
+ "grant_type": "refresh_token",
+ "refresh_token": refreshToken,
+ // TODO(nweiz): the spec recommends that HTTP basic auth be used in
+ // preference to form parameters, but Google doesn't support that.
+ // Should it be configurable?
+ "client_id": identifier,
+ "client_secret": secret
+ };
+ if (!scopes.isEmpty) fields["scope"] = Strings.join(scopes, ' ');
+
+ return httpClient.post(tokenEndpoint, fields: fields);
+ }).transform((response) {
+ return handleAccessTokenResponse(
+ response, tokenEndpoint, startTime, scopes);
+ }).transform((credentials) {
+ // The authorization server may issue a new refresh token. If it doesn't,
+ // we should re-use the one we already have.
+ if (credentials.refreshToken != null) return credentials;
+ return new Credentials(
+ credentials.accessToken,
+ this.refreshToken,
+ credentials.tokenEndpoint,
+ credentials.scopes,
+ credentials.expiration);
+ });
+ }
+}
diff --git a/pkg/oauth2/lib/src/expiration_exception.dart b/pkg/oauth2/lib/src/expiration_exception.dart
new file mode 100644
index 0000000..8c8ad1f
--- /dev/null
+++ b/pkg/oauth2/lib/src/expiration_exception.dart
@@ -0,0 +1,22 @@
+// 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.
+
+library expiration_exception;
+
+import 'dart:io';
+
+import 'credentials.dart';
+
+/// An exception raised when attempting to use expired OAuth2 credentials.
+class ExpirationException implements Exception {
+ /// The expired credentials.
+ final Credentials credentials;
+
+ /// Creates an ExpirationException.
+ ExpirationException(this.credentials);
+
+ /// Provides a string description of the ExpirationException.
+ String toString() =>
+ "OAuth2 credentials have expired and can't be refreshed.";
+}
diff --git a/pkg/oauth2/lib/src/handle_access_token_response.dart b/pkg/oauth2/lib/src/handle_access_token_response.dart
new file mode 100644
index 0000000..cb08d8f
--- /dev/null
+++ b/pkg/oauth2/lib/src/handle_access_token_response.dart
@@ -0,0 +1,145 @@
+// 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.
+
+library handle_access_token_response;
+
+import 'dart:io';
+import 'dart:json';
+import 'dart:uri';
+
+import '../../../http/lib/http.dart' as http;
+
+import 'credentials.dart';
+import 'authorization_exception.dart';
+
+/// The amount of time, in seconds, to add as a "grace period" for credential
+/// expiration. This allows credential expiration checks to remain valid for a
+/// reasonable amount of time.
+const _EXPIRATION_GRACE = 10;
+
+/// Handles a response from the authorization server that contains an access
+/// token. This response format is common across several different components of
+/// the OAuth2 flow.
+Credentials handleAccessTokenResponse(
+ http.Response response,
+ Uri tokenEndpoint,
+ Date startTime,
+ List<String> scopes) {
+ if (response.statusCode != 200) _handleErrorResponse(response, tokenEndpoint);
+
+ void validate(bool condition, String message) =>
+ _validate(response, tokenEndpoint, condition, message);
+
+ var contentType = response.headers['content-type'];
+ if (contentType != null) {
+ contentType = new ContentType.fromString(contentType);
+ }
+ validate(contentType != null && contentType.value == "application/json",
+ 'content-type was "$contentType", expected "application/json"');
+
+ var parameters;
+ try {
+ parameters = JSON.parse(response.body);
+ } catch (e) {
+ // TODO(nweiz): narrow this catch clause once issue 6775 is fixed.
+ validate(false, 'invalid JSON');
+ }
+
+ for (var requiredParameter in ['access_token', 'token_type']) {
+ validate(parameters.containsKey(requiredParameter),
+ 'did not contain required parameter "$requiredParameter"');
+ validate(parameters[requiredParameter] is String,
+ 'required parameter "$requiredParameter" was not a string, was '
+ '"${parameters[requiredParameter]}"');
+ }
+
+ // TODO(nweiz): support the "mac" token type
+ // (http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01)
+ validate(parameters['token_type'].toLowerCase() == 'bearer',
+ '"$tokenEndpoint": unknown token type "${parameters['token_type']}"');
+
+ var expiresIn = parameters['expires_in'];
+ validate(expiresIn == null || expiresIn is int,
+ 'parameter "expires_in" was not an int, was "$expiresIn"');
+
+ for (var name in ['refresh_token', 'scope']) {
+ var value = parameters[name];
+ validate(value == null || value is String,
+ 'parameter "$name" was not a string, was "$value"');
+ }
+
+ var scope = parameters['scope'];
+ if (scope != null) scopes = scope.split(" ");
+
+ var expiration = expiresIn == null ? null :
+ startTime.add(new Duration(seconds: expiresIn - _EXPIRATION_GRACE));
+
+ return new Credentials(
+ parameters['access_token'],
+ parameters['refresh_token'],
+ tokenEndpoint,
+ scopes,
+ expiration);
+}
+
+/// Throws the appropriate exception for an error response from the
+/// authorization server.
+void _handleErrorResponse(http.Response response, Uri tokenEndpoint) {
+ void validate(bool condition, String message) =>
+ _validate(response, tokenEndpoint, condition, message);
+
+ // OAuth2 mandates a 400 or 401 response code for access token error
+ // responses. If it's not a 400 reponse, the server is either broken or
+ // off-spec.
+ if (response.statusCode != 400 && response.statusCode != 401) {
+ var reason = '';
+ if (response.reasonPhrase != null && !response.reasonPhrase.isEmpty) {
+ ' ${response.reasonPhrase}';
+ }
+ throw new FormatException('OAuth request for "$tokenEndpoint" failed '
+ 'with status ${response.statusCode}$reason.\n\n${response.body}');
+ }
+
+ var contentType = response.headers['content-type'];
+ if (contentType != null) {
+ contentType = new ContentType.fromString(contentType);
+ }
+ validate(contentType != null && contentType.value == "application/json",
+ 'content-type was "$contentType", expected "application/json"');
+
+ var parameters;
+ try {
+ parameters = JSON.parse(response.body);
+ } catch (e) {
+ // TODO(nweiz): narrow this catch clause once issue 6775 is fixed.
+ validate(false, 'invalid JSON');
+ }
+
+ validate(parameters.containsKey('error'),
+ 'did not contain required parameter "error"');
+ validate(parameters["error"] is String,
+ 'required parameter "error" was not a string, was '
+ '"${parameters["error"]}"');
+
+ for (var name in ['error_description', 'error_uri']) {
+ var value = parameters[name];
+ validate(value == null || value is String,
+ 'parameter "$name" was not a string, was "$value"');
+ }
+
+ var description = parameters['error_description'];
+ var uriString = parameters['error_uri'];
+ var uri = uriString == null ? null : new Uri.fromString(uriString);
+ throw new AuthorizationException(parameters['error'], description, uri);
+}
+
+void _validate(
+ http.Response response,
+ Uri tokenEndpoint,
+ bool condition,
+ String message) {
+ if (condition) return;
+ throw new FormatException('Invalid OAuth response for "$tokenEndpoint": '
+ '$message.\n\n${response.body}');
+}
diff --git a/pkg/oauth2/lib/src/utils.dart b/pkg/oauth2/lib/src/utils.dart
new file mode 100644
index 0000000..583a5bc
--- /dev/null
+++ b/pkg/oauth2/lib/src/utils.dart
@@ -0,0 +1,73 @@
+// 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.
+
+library utils;
+
+import 'dart:uri';
+import 'dart:isolate';
+import 'dart:crypto';
+
+/// Adds additional query parameters to [url], overwriting the original
+/// parameters if a name conflict occurs.
+Uri addQueryParameters(Uri url, Map<String, String> parameters) {
+ var queryMap = queryToMap(url.query);
+ mapAddAll(queryMap, parameters);
+ return url.resolve("?${mapToQuery(queryMap)}");
+}
+
+/// Convert a URL query string (or `application/x-www-form-urlencoded` body)
+/// into a [Map] from parameter names to values.
+Map<String, String> queryToMap(String queryList) {
+ var map = <String>{};
+ for (var pair in queryList.split("&")) {
+ var split = split1(pair, "=");
+ if (split.isEmpty) continue;
+ var key = urlDecode(split[0]);
+ var value = split.length > 1 ? urlDecode(split[1]) : "";
+ map[key] = value;
+ }
+ return map;
+}
+
+/// Convert a [Map] from parameter names to values to a URL query string.
+String mapToQuery(Map<String, String> map) {
+ var pairs = <List<String>>[];
+ map.forEach((key, value) {
+ key = encodeUriComponent(key);
+ value = (value == null || value.isEmpty) ? null : encodeUriComponent(value);
+ pairs.add([key, value]);
+ });
+ return Strings.join(pairs.map((pair) {
+ if (pair[1] == null) return pair[0];
+ return "${pair[0]}=${pair[1]}";
+ }), "&");
+}
+
+/// Add all key/value pairs from [source] to [destination], overwriting any
+/// pre-existing values.
+void mapAddAll(Map destination, Map source) =>
+ source.forEach((key, value) => destination[key] = value);
+
+/// Decode a URL-encoded string. Unlike [decodeUriComponent], this includes
+/// replacing `+` with ` `.
+String urlDecode(String encoded) =>
+ decodeUriComponent(encoded.replaceAll("+", " "));
+
+/// Like [String.split], but only splits on the first occurrence of the pattern.
+/// This will always return a list of two elements or fewer.
+List<String> split1(String toSplit, String pattern) {
+ if (toSplit.isEmpty) return <String>[];
+
+ var index = toSplit.indexOf(pattern);
+ if (index == -1) return [toSplit];
+ return [toSplit.substring(0, index),
+ toSplit.substring(index + pattern.length)];
+}
+
+/// Returns a [Future] that asynchronously completes to `null`.
+Future get async {
+ var completer = new Completer();
+ new Timer(0, (_) => completer.complete(null));
+ return completer.future;
+}
diff --git a/pkg/oauth2/test/authorization_code_grant_test.dart b/pkg/oauth2/test/authorization_code_grant_test.dart
new file mode 100644
index 0000000..c4ccc21
--- /dev/null
+++ b/pkg/oauth2/test/authorization_code_grant_test.dart
@@ -0,0 +1,196 @@
+// 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.
+
+library authorization_code_grant_test;
+
+import 'dart:io';
+import 'dart:json';
+import 'dart:uri';
+
+import '../../unittest/lib/unittest.dart';
+import '../../http/lib/http.dart' as http;
+import '../../http/lib/testing.dart';
+import '../lib/oauth2.dart' as oauth2;
+import 'utils.dart';
+
+final redirectUrl = new Uri.fromString('http://example.com/redirect');
+
+ExpectClient client;
+
+oauth2.AuthorizationCodeGrant grant;
+
+void createGrant() {
+ client = new ExpectClient();
+ grant = new oauth2.AuthorizationCodeGrant(
+ 'identifier',
+ 'secret',
+ new Uri.fromString('https://example.com/authorization'),
+ new Uri.fromString('https://example.com/token'),
+ httpClient: client);
+}
+
+void main() {
+ group('.getAuthorizationUrl', () {
+ setUp(createGrant);
+
+ test('builds the correct URL', () {
+ expect(grant.getAuthorizationUrl(redirectUrl).toString(),
+ equals('https://example.com/authorization'
+ '?response_type=code'
+ '&client_id=identifier'
+ '&redirect_uri=http%3A%2F%2Fexample.com%2Fredirect'));
+ });
+
+ test('builds the correct URL with scopes', () {
+ var authorizationUrl = grant.getAuthorizationUrl(
+ redirectUrl, scopes: ['scope', 'other/scope']);
+ expect(authorizationUrl.toString(),
+ equals('https://example.com/authorization'
+ '?response_type=code'
+ '&client_id=identifier'
+ '&redirect_uri=http%3A%2F%2Fexample.com%2Fredirect'
+ '&scope=scope%20other%2Fscope'));
+ });
+
+ test('builds the correct URL with state', () {
+ var authorizationUrl = grant.getAuthorizationUrl(
+ redirectUrl, state: 'state');
+ expect(authorizationUrl.toString(),
+ equals('https://example.com/authorization'
+ '?response_type=code'
+ '&client_id=identifier'
+ '&redirect_uri=http%3A%2F%2Fexample.com%2Fredirect'
+ '&state=state'));
+ });
+
+ test('merges with existing query parameters', () {
+ grant = new oauth2.AuthorizationCodeGrant(
+ 'identifier',
+ 'secret',
+ new Uri.fromString('https://example.com/authorization?query=value'),
+ new Uri.fromString('https://example.com/token'),
+ httpClient: client);
+
+ var authorizationUrl = grant.getAuthorizationUrl(redirectUrl);
+ expect(authorizationUrl.toString(),
+ equals('https://example.com/authorization'
+ '?query=value'
+ '&response_type=code'
+ '&client_id=identifier'
+ '&redirect_uri=http%3A%2F%2Fexample.com%2Fredirect'));
+ });
+
+ test("can't be called twice", () {
+ grant.getAuthorizationUrl(redirectUrl);
+ expect(() => grant.getAuthorizationUrl(redirectUrl), throwsStateError);
+ });
+ });
+
+ group('.handleAuthorizationResponse', () {
+ setUp(createGrant);
+
+ test("can't be called before .getAuthorizationUrl", () {
+ expect(grant.handleAuthorizationResponse({}), throwsStateError);
+ });
+
+ test("can't be called twice", () {
+ grant.getAuthorizationUrl(redirectUrl);
+ grant.handleAuthorizationResponse({'code': 'auth code'});
+ expect(grant.handleAuthorizationResponse({'code': 'auth code'}),
+ throwsStateError);
+ });
+
+ test('must have a state parameter if the authorization URL did', () {
+ grant.getAuthorizationUrl(redirectUrl, state: 'state');
+ expect(grant.handleAuthorizationResponse({'code': 'auth code'}),
+ throwsFormatException);
+ });
+
+ test('must have the same state parameter the authorization URL did', () {
+ grant.getAuthorizationUrl(redirectUrl, state: 'state');
+ expect(grant.handleAuthorizationResponse({
+ 'code': 'auth code',
+ 'state': 'other state'
+ }), throwsFormatException);
+ });
+
+ test('must have a code parameter', () {
+ grant.getAuthorizationUrl(redirectUrl);
+ expect(grant.handleAuthorizationResponse({}), throwsFormatException);
+ });
+
+ test('with an error parameter throws an AuthorizationException', () {
+ grant.getAuthorizationUrl(redirectUrl);
+ expect(grant.handleAuthorizationResponse({'error': 'invalid_request'}),
+ throwsAuthorizationException);
+ });
+
+ test('sends an authorization code request', () {
+ grant.getAuthorizationUrl(redirectUrl);
+ client.expectRequest((request) {
+ expect(request.method, equals('POST'));
+ expect(request.url.toString(), equals(grant.tokenEndpoint.toString()));
+ expect(request.bodyFields, equals({
+ 'grant_type': 'authorization_code',
+ 'code': 'auth code',
+ 'redirect_uri': redirectUrl.toString(),
+ 'client_id': 'identifier',
+ 'client_secret': 'secret'
+ }));
+
+ return new Future.immediate(new http.Response(JSON.stringify({
+ 'access_token': 'access token',
+ 'token_type': 'bearer',
+ }), 200, headers: {'content-type': 'application/json'}));
+ });
+
+ expect(grant.handleAuthorizationResponse({'code': 'auth code'}),
+ completion(predicate((client) {
+ expect(client.credentials.accessToken, equals('access token'));
+ return true;
+ })));
+ });
+ });
+
+ group('.handleAuthorizationCode', () {
+ setUp(createGrant);
+
+ test("can't be called before .getAuthorizationUrl", () {
+ expect(grant.handleAuthorizationCode('auth code'), throwsStateError);
+ });
+
+ test("can't be called twice", () {
+ grant.getAuthorizationUrl(redirectUrl);
+ grant.handleAuthorizationCode('auth code');
+ expect(grant.handleAuthorizationCode('auth code'),
+ throwsStateError);
+ });
+
+ test('sends an authorization code request', () {
+ grant.getAuthorizationUrl(redirectUrl);
+ client.expectRequest((request) {
+ expect(request.method, equals('POST'));
+ expect(request.url.toString(), equals(grant.tokenEndpoint.toString()));
+ expect(request.bodyFields, equals({
+ 'grant_type': 'authorization_code',
+ 'code': 'auth code',
+ 'redirect_uri': redirectUrl.toString(),
+ 'client_id': 'identifier',
+ 'client_secret': 'secret'
+ }));
+
+ return new Future.immediate(new http.Response(JSON.stringify({
+ 'access_token': 'access token',
+ 'token_type': 'bearer',
+ }), 200, headers: {'content-type': 'application/json'}));
+ });
+
+ expect(grant.handleAuthorizationCode('auth code'),
+ completion(predicate((client) {
+ expect(client.credentials.accessToken, equals('access token'));
+ return true;
+ })));
+ });
+ });
+}
diff --git a/pkg/oauth2/test/client_test.dart b/pkg/oauth2/test/client_test.dart
new file mode 100644
index 0000000..94b7920
--- /dev/null
+++ b/pkg/oauth2/test/client_test.dart
@@ -0,0 +1,120 @@
+// 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.
+
+library client_test;
+
+import 'dart:io';
+import 'dart:json';
+import 'dart:uri';
+
+import '../../unittest/lib/unittest.dart';
+import '../../http/lib/http.dart' as http;
+import '../lib/oauth2.dart' as oauth2;
+import 'utils.dart';
+
+final Uri requestUri = new Uri.fromString("http://example.com/resource");
+
+final Uri tokenEndpoint = new Uri.fromString('http://example.com/token');
+
+ExpectClient httpClient;
+
+void createHttpClient() {
+ httpClient = new ExpectClient();
+}
+
+void main() {
+ group('with expired credentials', () {
+ setUp(createHttpClient);
+
+ test("that can't be refreshed throws an ExpirationException on send", () {
+ var expiration = new Date.now().subtract(new Duration(hours: 1));
+ var credentials = new oauth2.Credentials(
+ 'access token', null, null, [], expiration);
+ var client = new oauth2.Client('identifier', 'secret', credentials,
+ httpClient: httpClient);
+
+ expect(client.get(requestUri), throwsExpirationException);
+ });
+
+ test("that can be refreshed refreshes the credentials and sends the "
+ "request", () {
+ var expiration = new Date.now().subtract(new Duration(hours: 1));
+ var credentials = new oauth2.Credentials(
+ 'access token', 'refresh token', tokenEndpoint, [], expiration);
+ var client = new oauth2.Client('identifier', 'secret', credentials,
+ httpClient: httpClient);
+
+ httpClient.expectRequest((request) {
+ expect(request.method, equals('POST'));
+ expect(request.url.toString(), equals(tokenEndpoint.toString()));
+ return new Future.immediate(new http.Response(JSON.stringify({
+ 'access_token': 'new access token',
+ 'token_type': 'bearer'
+ }), 200, headers: {'content-type': 'application/json'}));
+ });
+
+ httpClient.expectRequest((request) {
+ expect(request.method, equals('GET'));
+ expect(request.url.toString(), equals(requestUri.toString()));
+ expect(request.headers['authorization'],
+ equals('Bearer new access token'));
+
+ return new Future.immediate(new http.Response('good job', 200));
+ });
+
+ expect(client.read(requestUri).transform((_) {
+ expect(client.credentials.accessToken, equals('new access token'));
+ }), completes);
+ });
+ });
+
+ group('with valid credentials', () {
+ setUp(createHttpClient);
+
+ test("sends a request with bearer authorization", () {
+ var credentials = new oauth2.Credentials('access token');
+ var client = new oauth2.Client('identifier', 'secret', credentials,
+ httpClient: httpClient);
+
+ httpClient.expectRequest((request) {
+ expect(request.method, equals('GET'));
+ expect(request.url.toString(), equals(requestUri.toString()));
+ expect(request.headers['authorization'],
+ equals('Bearer access token'));
+
+ return new Future.immediate(new http.Response('good job', 200));
+ });
+
+ expect(client.read(requestUri), completion(equals('good job')));
+ });
+
+ test("can manually refresh the credentials", () {
+ var credentials = new oauth2.Credentials(
+ 'access token', 'refresh token', tokenEndpoint);
+ var client = new oauth2.Client('identifier', 'secret', credentials,
+ httpClient: httpClient);
+
+ httpClient.expectRequest((request) {
+ expect(request.method, equals('POST'));
+ expect(request.url.toString(), equals(tokenEndpoint.toString()));
+ return new Future.immediate(new http.Response(JSON.stringify({
+ 'access_token': 'new access token',
+ 'token_type': 'bearer'
+ }), 200, headers: {'content-type': 'application/json'}));
+ });
+
+ expect(client.refreshCredentials().transform((_) {
+ expect(client.credentials.accessToken, equals('new access token'));
+ }), completes);
+ });
+
+ test("without a refresh token can't manually refresh the credentials", () {
+ var credentials = new oauth2.Credentials('access token');
+ var client = new oauth2.Client('identifier', 'secret', credentials,
+ httpClient: httpClient);
+
+ expect(client.refreshCredentials(), throwsStateError);
+ });
+ });
+}
diff --git a/pkg/oauth2/test/credentials_test.dart b/pkg/oauth2/test/credentials_test.dart
new file mode 100644
index 0000000..5faf2d0
--- /dev/null
+++ b/pkg/oauth2/test/credentials_test.dart
@@ -0,0 +1,174 @@
+// 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.
+
+library credentials_test;
+
+import 'dart:io';
+import 'dart:json';
+import 'dart:uri';
+
+import '../../unittest/lib/unittest.dart';
+import '../../http/lib/http.dart' as http;
+import '../lib/oauth2.dart' as oauth2;
+import 'utils.dart';
+
+final Uri tokenEndpoint = new Uri.fromString('http://example.com/token');
+
+ExpectClient httpClient;
+
+void main() {
+ setUp(() => httpClient = new ExpectClient());
+
+ test('is not expired if no expiration exists', () {
+ var credentials = new oauth2.Credentials('access token');
+ expect(credentials.isExpired, isFalse);
+ });
+
+ test('is not expired if the expiration is in the future', () {
+ var expiration = new Date.now().add(new Duration(hours: 1));
+ var credentials = new oauth2.Credentials(
+ 'access token', null, null, null, expiration);
+ expect(credentials.isExpired, isFalse);
+ });
+
+ test('is expired if the expiration is in the past', () {
+ var expiration = new Date.now().subtract(new Duration(hours: 1));
+ var credentials = new oauth2.Credentials(
+ 'access token', null, null, null, expiration);
+ expect(credentials.isExpired, isTrue);
+ });
+
+ test("can't refresh without a refresh token", () {
+ var credentials = new oauth2.Credentials(
+ 'access token', null, tokenEndpoint);
+ expect(credentials.canRefresh, false);
+ expect(credentials.refresh('identifier', 'secret', httpClient: httpClient),
+ throwsStateError);
+ });
+
+ test("can't refresh without a token endpoint", () {
+ var credentials = new oauth2.Credentials('access token', 'refresh token');
+ expect(credentials.canRefresh, false);
+ expect(credentials.refresh('identifier', 'secret', httpClient: httpClient),
+ throwsStateError);
+ });
+
+ test("can refresh with a refresh token and a token endpoint", () {
+ var credentials = new oauth2.Credentials(
+ 'access token', 'refresh token', tokenEndpoint, ['scope1', 'scope2']);
+ expect(credentials.canRefresh, true);
+
+ httpClient.expectRequest((request) {
+ expect(request.method, equals('POST'));
+ expect(request.url.toString(), equals(tokenEndpoint.toString()));
+ expect(request.bodyFields, equals({
+ "grant_type": "refresh_token",
+ "refresh_token": "refresh token",
+ "scope": "scope1 scope2",
+ "client_id": "identifier",
+ "client_secret": "secret"
+ }));
+
+ return new Future.immediate(new http.Response(JSON.stringify({
+ 'access_token': 'new access token',
+ 'token_type': 'bearer',
+ 'refresh_token': 'new refresh token'
+ }), 200, headers: {'content-type': 'application/json'}));
+ });
+
+
+ expect(credentials.refresh('identifier', 'secret', httpClient: httpClient)
+ .transform((credentials) {
+ expect(credentials.accessToken, equals('new access token'));
+ expect(credentials.refreshToken, equals('new refresh token'));
+ }), completes);
+ });
+
+ test("uses the old refresh token if a new one isn't provided", () {
+ var credentials = new oauth2.Credentials(
+ 'access token', 'refresh token', tokenEndpoint);
+ expect(credentials.canRefresh, true);
+
+ httpClient.expectRequest((request) {
+ expect(request.method, equals('POST'));
+ expect(request.url.toString(), equals(tokenEndpoint.toString()));
+ expect(request.bodyFields, equals({
+ "grant_type": "refresh_token",
+ "refresh_token": "refresh token",
+ "client_id": "identifier",
+ "client_secret": "secret"
+ }));
+
+ return new Future.immediate(new http.Response(JSON.stringify({
+ 'access_token': 'new access token',
+ 'token_type': 'bearer'
+ }), 200, headers: {'content-type': 'application/json'}));
+ });
+
+
+ expect(credentials.refresh('identifier', 'secret', httpClient: httpClient)
+ .transform((credentials) {
+ expect(credentials.accessToken, equals('new access token'));
+ expect(credentials.refreshToken, equals('refresh token'));
+ }), completes);
+ });
+
+ group("fromJson", () {
+ oauth2.Credentials fromMap(Map map) =>
+ new oauth2.Credentials.fromJson(JSON.stringify(map));
+
+ test("should load the same credentials from toJson", () {
+ var expiration = new Date.now().subtract(new Duration(hours: 1));
+ var credentials = new oauth2.Credentials(
+ 'access token', 'refresh token', tokenEndpoint, ['scope1', 'scope2'],
+ expiration);
+ var reloaded = new oauth2.Credentials.fromJson(credentials.toJson());
+
+ expect(reloaded.accessToken, equals(credentials.accessToken));
+ expect(reloaded.refreshToken, equals(credentials.refreshToken));
+ expect(reloaded.tokenEndpoint.toString(),
+ equals(credentials.tokenEndpoint.toString()));
+ expect(reloaded.scopes, equals(credentials.scopes));
+ expect(reloaded.expiration, equals(credentials.expiration));
+ });
+
+ test("should throw a FormatException for invalid JSON", () {
+ expect(() => new oauth2.Credentials.fromJson("foo bar"),
+ throwsFormatException);
+ });
+
+ test("should throw a FormatException for JSON that's not a map", () {
+ expect(() => new oauth2.Credentials.fromJson("null"),
+ throwsFormatException);
+ });
+
+ test("should throw a FormatException if there is no accessToken", () {
+ expect(() => fromMap({}), throwsFormatException);
+ });
+
+ test("should throw a FormatException if accessToken is not a string", () {
+ expect(() => fromMap({"accessToken": 12}), throwsFormatException);
+ });
+
+ test("should throw a FormatException if refreshToken is not a string", () {
+ expect(() => fromMap({"accessToken": "foo", "refreshToken": 12}),
+ throwsFormatException);
+ });
+
+ test("should throw a FormatException if tokenEndpoint is not a string", () {
+ expect(() => fromMap({"accessToken": "foo", "tokenEndpoint": 12}),
+ throwsFormatException);
+ });
+
+ test("should throw a FormatException if scopes is not a list", () {
+ expect(() => fromMap({"accessToken": "foo", "scopes": 12}),
+ throwsFormatException);
+ });
+
+ test("should throw a FormatException if expiration is not an int", () {
+ expect(() => fromMap({"accessToken": "foo", "expiration": "12"}),
+ throwsFormatException);
+ });
+ });
+}
diff --git a/pkg/oauth2/test/handle_access_token_response_test.dart b/pkg/oauth2/test/handle_access_token_response_test.dart
new file mode 100644
index 0000000..4757dc1
--- /dev/null
+++ b/pkg/oauth2/test/handle_access_token_response_test.dart
@@ -0,0 +1,191 @@
+// 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.
+
+library handle_access_token_response_test;
+
+import 'dart:io';
+import 'dart:json';
+import 'dart:uri';
+
+import '../../unittest/lib/unittest.dart';
+import '../../http/lib/http.dart' as http;
+import '../lib/oauth2.dart' as oauth2;
+import '../lib/src/handle_access_token_response.dart';
+import 'utils.dart';
+
+final Uri tokenEndpoint = new Uri.fromString("https://example.com/token");
+
+final Date startTime = new Date.now();
+
+oauth2.Credentials handle(http.Response response) =>
+ handleAccessTokenResponse(response, tokenEndpoint, startTime, ["scope"]);
+
+void main() {
+ group('an error response', () {
+ oauth2.Credentials handleError(
+ {String body: '{"error": "invalid_request"}',
+ int statusCode: 400,
+ Map<String, String> headers:
+ const {"content-type": "application/json"}}) =>
+ handle(new http.Response(body, statusCode, headers: headers));
+
+ test('causes an AuthorizationException', () {
+ expect(() => handleError(), throwsAuthorizationException);
+ });
+
+ test('with a 401 code causes an AuthorizationException', () {
+ expect(() => handleError(statusCode: 401), throwsAuthorizationException);
+ });
+
+ test('with an unexpected code causes a FormatException', () {
+ expect(() => handleError(statusCode: 500),
+ throwsFormatException);
+ });
+
+ test('with no content-type causes a FormatException', () {
+ expect(() => handleError(headers: {}), throwsFormatException);
+ });
+
+ test('with a non-JSON content-type causes a FormatException', () {
+ expect(() => handleError(headers: {
+ 'content-type': 'text/plain'
+ }), throwsFormatException);
+ });
+
+ test('with a JSON content-type and charset causes an '
+ 'AuthorizationException', () {
+ expect(() => handleError(headers: {
+ 'content-type': 'application/json; charset=UTF-8'
+ }), throwsAuthorizationException);
+ });
+
+ test('with invalid JSON causes a FormatException', () {
+ expect(() => handleError(body: 'not json'),
+ throwsFormatException);
+ });
+
+ test('with a non-string error causes a FormatException', () {
+ expect(() => handleError(body: '{"error": 12}'),
+ throwsFormatException);
+ });
+
+ test('with a non-string error_description causes a FormatException', () {
+ expect(() => handleError(body: JSON.stringify({
+ "error": "invalid_request",
+ "error_description": 12
+ })), throwsFormatException);
+ });
+
+ test('with a non-string error_uri causes a FormatException', () {
+ expect(() => handleError(body: JSON.stringify({
+ "error": "invalid_request",
+ "error_uri": 12
+ })), throwsFormatException);
+ });
+
+ test('with a string error_description causes a AuthorizationException', () {
+ expect(() => handleError(body: JSON.stringify({
+ "error": "invalid_request",
+ "error_description": "description"
+ })), throwsAuthorizationException);
+ });
+
+ test('with a string error_uri causes a AuthorizationException', () {
+ expect(() => handleError(body: JSON.stringify({
+ "error": "invalid_request",
+ "error_uri": "http://example.com/error"
+ })), throwsAuthorizationException);
+ });
+ });
+
+ group('a success response', () {
+ oauth2.Credentials handleSuccess(
+ {String contentType: "application/json",
+ accessToken: 'access token',
+ tokenType: 'bearer',
+ expiresIn,
+ refreshToken,
+ scope}) {
+ return handle(new http.Response(JSON.stringify({
+ 'access_token': accessToken,
+ 'token_type': tokenType,
+ 'expires_in': expiresIn,
+ 'refresh_token': refreshToken,
+ 'scope': scope
+ }), 200, headers: {'content-type': contentType}));
+ }
+
+ test('returns the correct credentials', () {
+ var credentials = handleSuccess();
+ expect(credentials.accessToken, equals('access token'));
+ expect(credentials.tokenEndpoint.toString(),
+ equals(tokenEndpoint.toString()));
+ });
+
+ test('with no content-type causes a FormatException', () {
+ expect(() => handleSuccess(contentType: null), throwsFormatException);
+ });
+
+ test('with a non-JSON content-type causes a FormatException', () {
+ expect(() => handleSuccess(contentType: 'text/plain'),
+ throwsFormatException);
+ });
+
+ test('with a JSON content-type and charset returns the correct '
+ 'credentials', () {
+ var credentials = handleSuccess(
+ contentType: 'application/json; charset=UTF-8');
+ expect(credentials.accessToken, equals('access token'));
+ });
+
+ test('with a null access token throws a FormatException', () {
+ expect(() => handleSuccess(accessToken: null), throwsFormatException);
+ });
+
+ test('with a non-string access token throws a FormatException', () {
+ expect(() => handleSuccess(accessToken: 12), throwsFormatException);
+ });
+
+ test('with a null token type throws a FormatException', () {
+ expect(() => handleSuccess(tokenType: null), throwsFormatException);
+ });
+
+ test('with a non-string token type throws a FormatException', () {
+ expect(() => handleSuccess(tokenType: 12), throwsFormatException);
+ });
+
+ test('with a non-"bearer" token type throws a FormatException', () {
+ expect(() => handleSuccess(tokenType: "mac"), throwsFormatException);
+ });
+
+ test('with a non-int expires-in throws a FormatException', () {
+ expect(() => handleSuccess(expiresIn: "whenever"), throwsFormatException);
+ });
+
+ test('with expires-in sets the expiration to ten seconds earlier than the '
+ 'server says', () {
+ var credentials = handleSuccess(expiresIn: 100);
+ expect(credentials.expiration.millisecondsSinceEpoch,
+ startTime.millisecondsSinceEpoch + 90 * 1000);
+ });
+
+ test('with a non-string refresh token throws a FormatException', () {
+ expect(() => handleSuccess(refreshToken: 12), throwsFormatException);
+ });
+
+ test('with a refresh token sets the refresh token', () {
+ var credentials = handleSuccess(refreshToken: "refresh me");
+ expect(credentials.refreshToken, equals("refresh me"));
+ });
+
+ test('with a non-string scope throws a FormatException', () {
+ expect(() => handleSuccess(scope: 12), throwsFormatException);
+ });
+
+ test('with a scope sets the scopes', () {
+ var credentials = handleSuccess(scope: "scope1 scope2");
+ expect(credentials.scopes, equals(["scope1", "scope2"]));
+ });
+ });
+}
diff --git a/pkg/oauth2/test/utils.dart b/pkg/oauth2/test/utils.dart
new file mode 100644
index 0000000..631ea95
--- /dev/null
+++ b/pkg/oauth2/test/utils.dart
@@ -0,0 +1,82 @@
+// 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.
+
+library utils;
+
+import '../../unittest/lib/unittest.dart';
+import '../../http/lib/http.dart' as http;
+import '../../http/lib/testing.dart';
+import '../lib/oauth2.dart' as oauth2;
+
+class ExpectClient extends MockClient {
+ final Queue<MockClientHandler> _handlers;
+
+ ExpectClient._(MockClientHandler fn)
+ : _handlers = new Queue<MockClientHandler>(),
+ super(fn);
+
+ factory ExpectClient() {
+ var client;
+ client = new ExpectClient._((request) =>
+ client._handleRequest(request));
+ return client;
+ }
+
+ void expectRequest(MockClientHandler fn) {
+ var completer = new Completer();
+ expect(completer.future, completes);
+
+ _handlers.add((request) {
+ completer.complete(null);
+ return fn(request);
+ });
+ }
+
+ Future<http.Response> _handleRequest(http.Request request) {
+ if (_handlers.isEmpty) {
+ return new Future.immediate(new http.Response('not found', 404));
+ } else {
+ return _handlers.removeFirst()(request);
+ }
+ }
+}
+
+// TODO(nweiz): remove this once it's built in to unittest
+/// A matcher for StateErrors.
+const isStateError = const _StateError();
+
+/// A matcher for functions that throw StateError.
+const Matcher throwsStateError =
+ const Throws(isStateError);
+
+class _StateError extends TypeMatcher {
+ const _StateError() : super("StateError");
+ bool matches(item, MatchState matchState) => item is StateError;
+}
+
+/// A matcher for AuthorizationExceptions.
+const isAuthorizationException = const _AuthorizationException();
+
+/// A matcher for functions that throw AuthorizationException.
+const Matcher throwsAuthorizationException =
+ const Throws(isAuthorizationException);
+
+class _AuthorizationException extends TypeMatcher {
+ const _AuthorizationException() : super("AuthorizationException");
+ bool matches(item, MatchState matchState) =>
+ item is oauth2.AuthorizationException;
+}
+
+/// A matcher for ExpirationExceptions.
+const isExpirationException = const _ExpirationException();
+
+/// A matcher for functions that throw ExpirationException.
+const Matcher throwsExpirationException =
+ const Throws(isExpirationException);
+
+class _ExpirationException extends TypeMatcher {
+ const _ExpirationException() : super("ExpirationException");
+ bool matches(item, MatchState matchState) =>
+ item is oauth2.ExpirationException;
+}
diff --git a/pkg/pkg.gyp b/pkg/pkg.gyp
new file mode 100644
index 0000000..e5c2c35
--- /dev/null
+++ b/pkg/pkg.gyp
@@ -0,0 +1,45 @@
+# 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.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'pkg_packages',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'action_name': 'make_pkg_packages',
+ 'inputs': [
+ '../tools/make_links.py',
+ 'args/lib',
+ 'fixnum/lib',
+ 'htmlescape/lib',
+ 'http/lib',
+ 'intl/lib',
+ 'logging/lib',
+ 'meta/lib',
+ 'unittest/lib',
+ 'webdriver/lib',
+ ],
+ 'outputs': [
+ '<(PRODUCT_DIR)/packages/args',
+ '<(PRODUCT_DIR)/packages/fixnum',
+ '<(PRODUCT_DIR)/packages/htmlescape',
+ '<(PRODUCT_DIR)/packages/http',
+ '<(PRODUCT_DIR)/packages/intl',
+ '<(PRODUCT_DIR)/packages/logging',
+ '<(PRODUCT_DIR)/packages/meta',
+ '<(PRODUCT_DIR)/packages/unittest',
+ '<(PRODUCT_DIR)/packages/webdriver',
+ ],
+ 'action': [
+ 'python', '../tools/make_links.py',
+ '<(PRODUCT_DIR)/packages',
+ '<@(_inputs)',
+ ],
+ },
+ ],
+ }
+ ],
+}
diff --git a/pkg/pkg.status b/pkg/pkg.status
index d7aadb7..32d4068 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -9,20 +9,18 @@
# arithmetic natively, i.e., the VM.
fixnum/test/int_64_vm_test: Skip
-# Skip the cURL tests until we have bundled binaries to run them on all
-# platforms.
-http/test/curl_client_test: Skip
-
[$compiler == dart2dart]
*: Skip
# Don't compiile tests that use dart:io to JS
[ $compiler == dart2js || $compiler == dart2dart || $compiler == dartc ]
http/test/*: Skip
+oauth2/test/*: Skip
# Skip tests that use local file access if we're running in any browser
[ $runtime == opera || $runtime == ff || $runtime == ie9 || $runtime == dartium || $runtime == chrome || $runtime == safari || $runtime == drt ]
http/test/*: Skip
+oauth2/test/*: Skip
intl/test/date_time_format_file_even_test: Skip
intl/test/date_time_format_file_odd_test: Skip
intl/test/find_default_locale_standalone_test: Skip
@@ -50,13 +48,11 @@
[ $compiler == dartc ]
unittest/test/mock_regexp_negative_test: Fail
unittest/test/mock_stepwise_negative_test: Fail
-
-[ $system == windows ]
-http/test/request_test: Pass, Timeout # Issue 6594
+args/test/args_test: Fail # http://dartbug.com/6790
[ $compiler == dart2js || $compiler == dartc ]
unittest/test/instance_test: Skip
[ $compiler == none && $runtime == drt ]
dartdoc/test/dartdoc_test: Skip # See dartbug.com/4541.
-
+args/test/args_test: Skip # http://dartbug.com/6744
diff --git a/pkg/unittest/lib/src/core_matchers.dart b/pkg/unittest/lib/src/core_matchers.dart
index 20e9db2..3846fdd 100644
--- a/pkg/unittest/lib/src/core_matchers.dart
+++ b/pkg/unittest/lib/src/core_matchers.dart
@@ -489,18 +489,6 @@
bool matches(item, MatchState matchState) => item is UnimplementedError;
}
-/** A matcher for NullPointerExceptions. */
-const isNullPointerException = const _NullPointerException();
-
-/** A matcher for functions that throw NotNullPointerException. */
-const Matcher throwsNullPointerException =
- const Throws(isNullPointerException);
-
-class _NullPointerException extends TypeMatcher {
- const _NullPointerException() : super("NullPointerException");
- bool matches(item, MatchState matchState) => item is NullPointerException;
-}
-
/** A matcher for UnsupportedError. */
const isUnsupportedError = const _UnsupportedError();
diff --git a/pkg/unittest/test/matchers_test.dart b/pkg/unittest/test/matchers_test.dart
index c9045ad..81be8fb 100644
--- a/pkg/unittest/test/matchers_test.dart
+++ b/pkg/unittest/test/matchers_test.dart
@@ -155,16 +155,6 @@
"UnimplementedError.");
});
- test('throwsNullPointerException', () {
- shouldPass(() { throw new NullPointerException(''); },
- throwsNullPointerException);
- shouldFail(() { throw new Exception(); },
- throwsNullPointerException,
- "Expected: throws an exception which matches NullPointerException "
- "but: exception <Exception> does not match "
- "NullPointerException.");
- });
-
test('throwsUnsupportedError', () {
shouldPass(() { throw new UnsupportedError(''); },
throwsUnsupportedError);
diff --git a/runtime/bin/bin.gypi b/runtime/bin/bin.gypi
index 084cd51..c8108b7 100644
--- a/runtime/bin/bin.gypi
+++ b/runtime/bin/bin.gypi
@@ -268,6 +268,10 @@
'builtin_natives.cc',
'builtin.h',
'io_natives.h',
+ 'log_android.cc',
+ 'log_linux.cc',
+ 'log_macos.cc',
+ 'log_win.cc',
],
'includes': [
'builtin_impl_sources.gypi',
@@ -391,7 +395,13 @@
'link_settings': {
'libraries': [ '-lws2_32.lib', '-lRpcrt4.lib' ],
},
- }]],
+ }],
+ ['OS=="android"', {
+ 'link_settings': {
+ 'libraries': [ '-llog' ],
+ },
+ }]
+ ],
},
{
# Generate snapshot bin file.
@@ -482,7 +492,14 @@
},
},
}],
- ],
+ ['OS=="linux"', {
+ # Have the linker add all symbols to the dynamic symbol table
+ # so that extensions can look them up dynamically in the binary.
+ 'ldflags': [
+ '-rdynamic',
+ ],
+ }],
+ ],
},
{
# dart binary without any snapshot built in.
@@ -521,7 +538,15 @@
'AdditionalOptions': [ '/EXPORT:Dart_True' ],
},
},
- }]],
+ }],
+ ['OS=="linux"', {
+ # Have the linker add all symbols to the dynamic symbol table
+ # so that extensions can look them up dynamically in the binary.
+ 'ldflags': [
+ '-rdynamic',
+ ],
+ }],
+ ],
},
{
'target_name': 'process_test',
diff --git a/runtime/bin/builtin.dart b/runtime/bin/builtin.dart
index 4aea641..f84a50f 100644
--- a/runtime/bin/builtin.dart
+++ b/runtime/bin/builtin.dart
@@ -71,12 +71,20 @@
var baseUri = new Uri.fromString(base);
_logResolution("# Resolving: $userString from $base");
- // Relative URIs with scheme dart-ext should be resolved as if with no scheme.
var uri = new Uri.fromString(userString);
var resolved;
if ('dart-ext' == uri.scheme) {
+ // Relative URIs with scheme dart-ext should be resolved as if with no
+ // scheme.
resolved = baseUri.resolve(uri.path);
- resolved = new Uri.fromComponents(scheme: "dart-ext", path: resolved.path);
+ var path = resolved.path;
+ if (resolved.scheme == 'package') {
+ // If we are resolving relative to a package URI we go directly to the
+ // file path and keep the dart-ext scheme. Otherwise, we will lose the
+ // package URI path part.
+ path = _filePathFromPackageUri(resolved);
+ }
+ resolved = new Uri.fromComponents(scheme: "dart-ext", path: path);
} else {
resolved = baseUri.resolve(userString);
}
diff --git a/runtime/bin/dbg_connection.cc b/runtime/bin/dbg_connection.cc
index 4c23dd4..4918d0d 100644
--- a/runtime/bin/dbg_connection.cc
+++ b/runtime/bin/dbg_connection.cc
@@ -5,6 +5,7 @@
#include "bin/dbg_connection.h"
#include "bin/dbg_message.h"
#include "bin/dartutils.h"
+#include "bin/log.h"
#include "bin/socket.h"
#include "bin/thread.h"
#include "bin/utils.h"
@@ -198,7 +199,8 @@
FATAL("Illegal JSON message received");
}
if (!found) {
- printf("'command' not found in JSON message: '%s'\n", msgbuf_->buf());
+ Log::Print("'command' not found in JSON message: '%s'\n",
+ msgbuf_->buf());
msgbuf_->PopMessage();
}
@@ -242,7 +244,7 @@
}
// This is an unrecognized command, report error and move on to next.
- printf("unrecognized command received: '%s'\n", msgbuf_->buf());
+ Log::Print("unrecognized command received: '%s'\n", msgbuf_->buf());
HandleUnknownMsg();
msgbuf_->PopMessage();
}
diff --git a/runtime/bin/dbg_connection_android.cc b/runtime/bin/dbg_connection_android.cc
index 7fe7e94..a0bce37 100644
--- a/runtime/bin/dbg_connection_android.cc
+++ b/runtime/bin/dbg_connection_android.cc
@@ -9,6 +9,7 @@
#include "bin/dbg_connection.h"
#include "bin/fdutils.h"
+#include "bin/log.h"
#include "bin/socket.h"
int DebuggerConnectionImpl::epoll_fd_ = -1;
@@ -32,7 +33,7 @@
// Sync message. Not yet implemented.
UNIMPLEMENTED();
} else {
- printf("unexpected: receiving debugger connection event.\n");
+ Log::Print("unexpected: receiving debugger connection event.\n");
UNIMPLEMENTED();
}
}
diff --git a/runtime/bin/dbg_connection_linux.cc b/runtime/bin/dbg_connection_linux.cc
index 7fe7e94..a0bce37 100644
--- a/runtime/bin/dbg_connection_linux.cc
+++ b/runtime/bin/dbg_connection_linux.cc
@@ -9,6 +9,7 @@
#include "bin/dbg_connection.h"
#include "bin/fdutils.h"
+#include "bin/log.h"
#include "bin/socket.h"
int DebuggerConnectionImpl::epoll_fd_ = -1;
@@ -32,7 +33,7 @@
// Sync message. Not yet implemented.
UNIMPLEMENTED();
} else {
- printf("unexpected: receiving debugger connection event.\n");
+ Log::Print("unexpected: receiving debugger connection event.\n");
UNIMPLEMENTED();
}
}
diff --git a/runtime/bin/dbg_connection_macos.cc b/runtime/bin/dbg_connection_macos.cc
index cc0f13a..8464abf 100644
--- a/runtime/bin/dbg_connection_macos.cc
+++ b/runtime/bin/dbg_connection_macos.cc
@@ -12,6 +12,7 @@
#include "bin/dartutils.h"
#include "bin/dbg_connection.h"
#include "bin/fdutils.h"
+#include "bin/log.h"
#include "bin/socket.h"
#include "platform/thread.h"
#include "platform/utils.h"
@@ -87,10 +88,10 @@
} else if (ident == wakeup_fds_[0]) {
Message msg;
if (ReceiveMessage(&msg)) {
- printf("Received sync message id %d.\n", msg.msg_id);
+ Log::Print("Received sync message id %d.\n", msg.msg_id);
}
} else {
- printf("unexpected: receiving debugger connection event.\n");
+ Log::Print("unexpected: receiving debugger connection event.\n");
UNIMPLEMENTED();
}
}
@@ -113,7 +114,7 @@
}
}
}
- printf("shutting down debugger thread\n");
+ Log::Print("shutting down debugger thread\n");
}
diff --git a/runtime/bin/directory_win.cc b/runtime/bin/directory_win.cc
index 9508dae..ca6c601 100644
--- a/runtime/bin/directory_win.cc
+++ b/runtime/bin/directory_win.cc
@@ -7,8 +7,7 @@
#include <errno.h>
#include <sys/stat.h>
-#include "bin/platform.h"
-
+#include "bin/log.h"
static int SetOsErrorMessage(char* os_error_message,
int os_error_message_len) {
@@ -23,7 +22,7 @@
NULL);
if (message_size == 0) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
- fprintf(stderr, "FormatMessage failed %d\n", GetLastError());
+ Log::PrintErr("FormatMessage failed %d\n", GetLastError());
}
snprintf(os_error_message, os_error_message_len, "OS Error %d", error_code);
}
diff --git a/runtime/bin/eventhandler_android.cc b/runtime/bin/eventhandler_android.cc
index de28f03..878c7eb 100644
--- a/runtime/bin/eventhandler_android.cc
+++ b/runtime/bin/eventhandler_android.cc
@@ -15,6 +15,7 @@
#include "bin/dartutils.h"
#include "bin/fdutils.h"
+#include "bin/log.h"
#include "platform/hashmap.h"
#include "platform/thread.h"
#include "platform/utils.h"
@@ -229,21 +230,21 @@
#ifdef DEBUG_POLL
static void PrintEventMask(intptr_t fd, intptr_t events) {
- printf("%d ", fd);
- if ((events & EPOLLIN) != 0) printf("EPOLLIN ");
- if ((events & EPOLLPRI) != 0) printf("EPOLLPRI ");
- if ((events & EPOLLOUT) != 0) printf("EPOLLOUT ");
- if ((events & EPOLLERR) != 0) printf("EPOLLERR ");
- if ((events & EPOLLHUP) != 0) printf("EPOLLHUP ");
- if ((events & EPOLLRDHUP) != 0) printf("EPOLLRDHUP ");
+ Log::Print("%d ", fd);
+ if ((events & EPOLLIN) != 0) Log::Print("EPOLLIN ");
+ if ((events & EPOLLPRI) != 0) Log::Print("EPOLLPRI ");
+ if ((events & EPOLLOUT) != 0) Log::Print("EPOLLOUT ");
+ if ((events & EPOLLERR) != 0) Log::Print("EPOLLERR ");
+ if ((events & EPOLLHUP) != 0) Log::Print("EPOLLHUP ");
+ if ((events & EPOLLRDHUP) != 0) Log::Print("EPOLLRDHUP ");
int all_events = EPOLLIN | EPOLLPRI | EPOLLOUT |
EPOLLERR | EPOLLHUP | EPOLLRDHUP;
if ((events & ~all_events) != 0) {
- printf("(and %08x) ", events & ~all_events);
+ Log::Print("(and %08x) ", events & ~all_events);
}
- printf("(available %d) ", FDUtils::AvailableBytes(fd));
+ Log::Print("(available %d) ", FDUtils::AvailableBytes(fd));
- printf("\n");
+ Log::Print("\n");
}
#endif
@@ -299,7 +300,7 @@
event_mask = (1 << kCloseEvent);
sd->MarkClosedRead();
} else if (errno != EWOULDBLOCK) {
- fprintf(stderr, "Error recv: %s\n", strerror(errno));
+ Log::PrintErr("Error recv: %s\n", strerror(errno));
}
}
}
diff --git a/runtime/bin/eventhandler_linux.cc b/runtime/bin/eventhandler_linux.cc
index 886388f3..49b6ca1 100644
--- a/runtime/bin/eventhandler_linux.cc
+++ b/runtime/bin/eventhandler_linux.cc
@@ -15,6 +15,7 @@
#include "bin/dartutils.h"
#include "bin/fdutils.h"
+#include "bin/log.h"
#include "platform/hashmap.h"
#include "platform/thread.h"
#include "platform/utils.h"
@@ -229,21 +230,21 @@
#ifdef DEBUG_POLL
static void PrintEventMask(intptr_t fd, intptr_t events) {
- printf("%d ", fd);
- if ((events & EPOLLIN) != 0) printf("EPOLLIN ");
- if ((events & EPOLLPRI) != 0) printf("EPOLLPRI ");
- if ((events & EPOLLOUT) != 0) printf("EPOLLOUT ");
- if ((events & EPOLLERR) != 0) printf("EPOLLERR ");
- if ((events & EPOLLHUP) != 0) printf("EPOLLHUP ");
- if ((events & EPOLLRDHUP) != 0) printf("EPOLLRDHUP ");
+ Log::Print("%d ", fd);
+ if ((events & EPOLLIN) != 0) Log::Print("EPOLLIN ");
+ if ((events & EPOLLPRI) != 0) Log::Print("EPOLLPRI ");
+ if ((events & EPOLLOUT) != 0) Log::Print("EPOLLOUT ");
+ if ((events & EPOLLERR) != 0) Log::Print("EPOLLERR ");
+ if ((events & EPOLLHUP) != 0) Log::Print("EPOLLHUP ");
+ if ((events & EPOLLRDHUP) != 0) Log::Print("EPOLLRDHUP ");
int all_events = EPOLLIN | EPOLLPRI | EPOLLOUT |
EPOLLERR | EPOLLHUP | EPOLLRDHUP;
if ((events & ~all_events) != 0) {
- printf("(and %08x) ", events & ~all_events);
+ Log::Print("(and %08x) ", events & ~all_events);
}
- printf("(available %d) ", FDUtils::AvailableBytes(fd));
+ Log::Print("(available %d) ", FDUtils::AvailableBytes(fd));
- printf("\n");
+ Log::Print("\n");
}
#endif
@@ -299,7 +300,7 @@
event_mask = (1 << kCloseEvent);
sd->MarkClosedRead();
} else if (errno != EWOULDBLOCK) {
- fprintf(stderr, "Error recv: %s\n", strerror(errno));
+ Log::PrintErr("Error recv: %s\n", strerror(errno));
}
}
}
diff --git a/runtime/bin/eventhandler_macos.cc b/runtime/bin/eventhandler_macos.cc
index 59a3d65..3954190 100644
--- a/runtime/bin/eventhandler_macos.cc
+++ b/runtime/bin/eventhandler_macos.cc
@@ -14,6 +14,7 @@
#include "bin/dartutils.h"
#include "bin/fdutils.h"
+#include "bin/log.h"
#include "platform/hashmap.h"
#include "platform/thread.h"
#include "platform/utils.h"
@@ -240,15 +241,16 @@
#ifdef DEBUG_KQUEUE
static void PrintEventMask(intptr_t fd, struct kevent* event) {
- printf("%d ", static_cast<int>(fd));
- if (event->filter == EVFILT_READ) printf("EVFILT_READ ");
- if (event->filter == EVFILT_WRITE) printf("EVFILT_WRITE ");
- printf("flags: %x: ", event->flags);
- if ((event->flags & EV_EOF) != 0) printf("EV_EOF ");
- if ((event->flags & EV_ERROR) != 0) printf("EV_ERROR ");
- printf("- fflags: %d ", event->fflags);
- printf("(available %d) ", static_cast<int>(FDUtils::AvailableBytes(fd)));
- printf("\n");
+ Log::Print("%d ", static_cast<int>(fd));
+ if (event->filter == EVFILT_READ) Log::Print("EVFILT_READ ");
+ if (event->filter == EVFILT_WRITE) Log::Print("EVFILT_WRITE ");
+ Log::Print("flags: %x: ", event->flags);
+ if ((event->flags & EV_EOF) != 0) Log::Print("EV_EOF ");
+ if ((event->flags & EV_ERROR) != 0) Log::Print("EV_ERROR ");
+ Log::Print("- fflags: %d ", event->fflags);
+ Log::Print("(available %d) ",
+ static_cast<int>(FDUtils::AvailableBytes(fd)));
+ Log::Print("\n");
}
#endif
diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc
index 2d4343b..bc2f480 100644
--- a/runtime/bin/eventhandler_win.cc
+++ b/runtime/bin/eventhandler_win.cc
@@ -11,6 +11,7 @@
#include "bin/builtin.h"
#include "bin/dartutils.h"
+#include "bin/log.h"
#include "bin/socket.h"
#include "platform/thread.h"
@@ -143,7 +144,7 @@
reinterpret_cast<ULONG_PTR>(this),
0);
if (completion_port_ == NULL) {
- fprintf(stderr, "Error CreateIoCompletionPort: %d\n", GetLastError());
+ Log::PrintErr("Error CreateIoCompletionPort: %d\n", GetLastError());
return false;
}
return true;
@@ -224,7 +225,7 @@
NULL);
if (!ok) {
if (GetLastError() != ERROR_BROKEN_PIPE) {
- fprintf(stderr, "ReadFile failed %d\n", GetLastError());
+ Log::PrintErr("ReadFile failed %d\n", GetLastError());
}
bytes_read = 0;
}
@@ -259,7 +260,7 @@
}
if (GetLastError() != ERROR_BROKEN_PIPE) {
- fprintf(stderr, "ReadFile failed: %d\n", GetLastError());
+ Log::PrintErr("ReadFile failed: %d\n", GetLastError());
}
event_handler_->HandleClosed(this);
IOBuffer::DisposeBuffer(buffer);
@@ -298,7 +299,7 @@
}
if (GetLastError() != ERROR_BROKEN_PIPE) {
- fprintf(stderr, "WriteFile failed: %d\n", GetLastError());
+ Log::PrintErr("WriteFile failed: %d\n", GetLastError());
}
event_handler_->HandleClosed(this);
IOBuffer::DisposeBuffer(buffer);
@@ -344,7 +345,7 @@
NULL,
NULL);
if (status == SOCKET_ERROR) {
- fprintf(stderr, "Error WSAIoctl failed: %d\n", WSAGetLastError());
+ Log::PrintErr("Error WSAIoctl failed: %d\n", WSAGetLastError());
return false;
}
return true;
@@ -376,7 +377,7 @@
buffer->GetCleanOverlapped());
if (!ok) {
if (WSAGetLastError() != WSA_IO_PENDING) {
- fprintf(stderr, "AcceptEx failed: %d\n", WSAGetLastError());
+ Log::PrintErr("AcceptEx failed: %d\n", WSAGetLastError());
closesocket(buffer->client());
IOBuffer::DisposeBuffer(buffer);
return false;
@@ -422,7 +423,7 @@
accepted_tail_ = client_socket;
}
} else {
- fprintf(stderr, "setsockopt failed: %d\n", WSAGetLastError());
+ Log::PrintErr("setsockopt failed: %d\n", WSAGetLastError());
closesocket(buffer->client());
}
}
@@ -514,7 +515,7 @@
NULL);
if (!ok) {
if (GetLastError() != ERROR_BROKEN_PIPE) {
- fprintf(stderr, "WriteFile failed: %d\n", GetLastError());
+ Log::PrintErr("WriteFile failed: %d\n", GetLastError());
}
event_handler_->HandleClosed(this);
}
@@ -526,7 +527,7 @@
void ClientSocket::Shutdown(int how) {
int rc = shutdown(socket(), how);
if (rc == SOCKET_ERROR) {
- fprintf(stderr, "shutdown failed: %d %d\n", socket(), WSAGetLastError());
+ Log::PrintErr("shutdown failed: %d %d\n", socket(), WSAGetLastError());
}
if (how == SD_RECEIVE) MarkClosedRead();
if (how == SD_SEND) MarkClosedWrite();
@@ -559,7 +560,7 @@
}
if (WSAGetLastError() != WSAECONNRESET) {
- fprintf(stderr, "WSARecv failed: %d\n", WSAGetLastError());
+ Log::PrintErr("WSARecv failed: %d\n", WSAGetLastError());
}
event_handler_->HandleClosed(this);
IOBuffer::DisposeBuffer(buffer);
@@ -584,7 +585,7 @@
return true;
}
- fprintf(stderr, "WSASend failed: %d\n", WSAGetLastError());
+ Log::PrintErr("WSASend failed: %d\n", WSAGetLastError());
IOBuffer::DisposeBuffer(pending_write_);
pending_write_ = NULL;
return false;
@@ -876,7 +877,7 @@
if (!ok && overlapped == NULL) {
if (GetLastError() == ERROR_ABANDONED_WAIT_0) {
// The completion port should never be closed.
- printf("Completion port closed\n");
+ Log::Print("Completion port closed\n");
UNREACHABLE();
} else {
// Timeout is signalled by false result and NULL in overlapped.
diff --git a/runtime/bin/extensions.cc b/runtime/bin/extensions.cc
index 244a631..d8b13f9 100644
--- a/runtime/bin/extensions.cc
+++ b/runtime/bin/extensions.cc
@@ -15,17 +15,18 @@
Dart_Handle Extensions::LoadExtension(const char* extension_url,
Dart_Handle parent_library) {
char* library_path = strdup(extension_url);
- if (!library_path || !File::IsAbsolutePath(library_path)) {
- free(library_path);
- return Dart_Error("unexpected error in library path");
+
+ if (library_path == NULL) {
+ return Dart_Error("Out of memory in LoadExtension");
}
+
// Extract the path and the extension name from the url.
char* last_path_separator = strrchr(library_path, '/');
char* extension_name = last_path_separator + 1;
*last_path_separator = '\0'; // Terminate library_path at last separator.
void* library_handle = LoadExtensionLibrary(library_path, extension_name);
- if (!library_handle) {
+ if (library_handle == NULL) {
free(library_path);
return Dart_Error("cannot find extension library");
}
diff --git a/runtime/bin/file_android.cc b/runtime/bin/file_android.cc
index 66e6251..ddcec13 100644
--- a/runtime/bin/file_android.cc
+++ b/runtime/bin/file_android.cc
@@ -11,6 +11,7 @@
#include <libgen.h>
#include "bin/builtin.h"
+#include "bin/log.h"
class FileHandle {
public:
@@ -42,7 +43,7 @@
const int kBufferSize = 1024;
char error_message[kBufferSize];
strerror_r(errno, error_message, kBufferSize);
- fprintf(stderr, "%s\n", error_message);
+ Log::PrintErr("%s\n", error_message);
}
handle_->set_fd(kClosedFd);
}
diff --git a/runtime/bin/file_linux.cc b/runtime/bin/file_linux.cc
index 66e6251..ddcec13 100644
--- a/runtime/bin/file_linux.cc
+++ b/runtime/bin/file_linux.cc
@@ -11,6 +11,7 @@
#include <libgen.h>
#include "bin/builtin.h"
+#include "bin/log.h"
class FileHandle {
public:
@@ -42,7 +43,7 @@
const int kBufferSize = 1024;
char error_message[kBufferSize];
strerror_r(errno, error_message, kBufferSize);
- fprintf(stderr, "%s\n", error_message);
+ Log::PrintErr("%s\n", error_message);
}
handle_->set_fd(kClosedFd);
}
diff --git a/runtime/bin/file_macos.cc b/runtime/bin/file_macos.cc
index b5bc95a..0fd0c8d 100644
--- a/runtime/bin/file_macos.cc
+++ b/runtime/bin/file_macos.cc
@@ -13,6 +13,7 @@
#include "bin/builtin.h"
#include "bin/fdutils.h"
+#include "bin/log.h"
class FileHandle {
public:
@@ -44,7 +45,7 @@
const int kBufferSize = 1024;
char error_message[kBufferSize];
strerror_r(errno, error_message, kBufferSize);
- fprintf(stderr, "%s\n", error_message);
+ Log::PrintErr("%s\n", error_message);
}
handle_->set_fd(kClosedFd);
}
diff --git a/runtime/bin/file_win.cc b/runtime/bin/file_win.cc
index 97a98a6..a9cef38 100644
--- a/runtime/bin/file_win.cc
+++ b/runtime/bin/file_win.cc
@@ -11,6 +11,7 @@
#include <sys/stat.h>
#include "bin/builtin.h"
+#include "bin/log.h"
class FileHandle {
public:
@@ -39,7 +40,7 @@
ASSERT(handle_->fd() >= 0);
int err = close(handle_->fd());
if (err != 0) {
- fprintf(stderr, "%s\n", strerror(errno));
+ Log::PrintErr("%s\n", strerror(errno));
}
handle_->set_fd(kClosedFd);
}
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index b3513e4..2f2c6f2 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -14,12 +14,14 @@
#include "bin/builtin.h"
#include "bin/dartutils.h"
#include "bin/file.h"
+#include "bin/log.h"
+
#include "platform/globals.h"
#define CHECK_RESULT(result) \
if (Dart_IsError(result)) { \
free(snapshot_buffer); \
- fprintf(stderr, "Error: %s", Dart_GetError(result)); \
+ Log::PrintErr("Error: %s", Dart_GetError(result)); \
Dart_ExitScope(); \
Dart_ShutdownIsolate(); \
exit(255); \
@@ -205,16 +207,14 @@
static void PrintUsage() {
- fprintf(stderr,
- "dart [<vm-flags>] "
- "[<dart-script-file>]\n");
+ Log::PrintErr("dart [<vm-flags>] [<dart-script-file>]\n");
}
static void VerifyLoaded(Dart_Handle library) {
if (Dart_IsError(library)) {
const char* err_msg = Dart_GetError(library);
- fprintf(stderr, "Errors encountered while loading: %s\n", err_msg);
+ Log::PrintErr("Errors encountered while loading: %s\n", err_msg);
Dart_ExitScope();
Dart_ShutdownIsolate();
exit(255);
@@ -251,7 +251,7 @@
// Set up the library tag handler for this isolate.
Dart_Handle result = Dart_SetLibraryTagHandler(DartUtils::LibraryTagHandler);
if (Dart_IsError(result)) {
- fprintf(stderr, "%s", Dart_GetError(result));
+ Log::PrintErr("%s", Dart_GetError(result));
Dart_ExitScope();
Dart_ShutdownIsolate();
exit(255);
@@ -290,7 +290,7 @@
}
if (snapshot_filename == NULL) {
- fprintf(stderr, "No snapshot output file specified\n");
+ Log::PrintErr("No snapshot output file specified\n");
return 255;
}
@@ -302,14 +302,14 @@
// Note: We don't expect isolates to be created from dart code during
// snapshot generation.
if (!Dart_Initialize(NULL, NULL, NULL)) {
- fprintf(stderr, "VM initialization failed\n");
+ Log::PrintErr("VM initialization failed\n");
return 255;
}
char* error;
Dart_Isolate isolate = Dart_CreateIsolate(NULL, NULL, NULL, NULL, &error);
if (isolate == NULL) {
- fprintf(stderr, "Error: %s", error);
+ Log::PrintErr("Error: %s", error);
free(error);
exit(255);
}
@@ -360,7 +360,7 @@
NULL,
&error);
if (isolate == NULL) {
- fprintf(stderr, "%s", error);
+ Log::PrintErr("%s", error);
free(error);
free(snapshot_buffer);
exit(255);
diff --git a/runtime/bin/io_impl_sources.gypi b/runtime/bin/io_impl_sources.gypi
index f86ca02..552ac3d 100644
--- a/runtime/bin/io_impl_sources.gypi
+++ b/runtime/bin/io_impl_sources.gypi
@@ -41,7 +41,7 @@
'socket_linux.cc',
'socket_macos.cc',
'socket_win.cc',
- 'tls_socket.cc',
- 'tls_socket.h',
+ 'secure_socket.cc',
+ 'secure_socket.h',
],
}
diff --git a/runtime/bin/io_natives.cc b/runtime/bin/io_natives.cc
index 1cd0236..16fd532 100644
--- a/runtime/bin/io_natives.cc
+++ b/runtime/bin/io_natives.cc
@@ -40,13 +40,13 @@
V(Socket_GetError, 1) \
V(Socket_GetStdioHandle, 2) \
V(Socket_NewServicePort, 0) \
- V(TlsSocket_Connect, 3) \
- V(TlsSocket_Destroy, 1) \
- V(TlsSocket_Handshake, 1) \
- V(TlsSocket_Init, 1) \
- V(TlsSocket_ProcessBuffer, 2) \
- V(TlsSocket_RegisterHandshakeCompleteCallback, 2) \
- V(TlsSocket_SetCertificateDatabase, 1)
+ V(SecureSocket_Connect, 5) \
+ V(SecureSocket_Destroy, 1) \
+ V(SecureSocket_Handshake, 1) \
+ V(SecureSocket_Init, 1) \
+ V(SecureSocket_ProcessBuffer, 2) \
+ V(SecureSocket_RegisterHandshakeCompleteCallback, 2) \
+ V(SecureSocket_SetCertificateDatabase, 2)
IO_NATIVE_LIST(DECLARE_FUNCTION);
diff --git a/runtime/bin/io_sources.gypi b/runtime/bin/io_sources.gypi
index 9300c1c..69100f0 100644
--- a/runtime/bin/io_sources.gypi
+++ b/runtime/bin/io_sources.gypi
@@ -14,6 +14,6 @@
'process_patch.dart',
'socket_patch.dart',
'stdio_patch.dart',
- 'tls_socket_patch.dart',
+ 'secure_socket_patch.dart',
],
}
diff --git a/runtime/bin/log.h b/runtime/bin/log.h
new file mode 100644
index 0000000..c495840
--- /dev/null
+++ b/runtime/bin/log.h
@@ -0,0 +1,37 @@
+// 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.
+
+#ifndef BIN_LOG_H_
+#define BIN_LOG_H_
+
+#include <stdarg.h>
+
+#include "platform/globals.h"
+
+class Log {
+ public:
+ // Print formatted output for debugging.
+ static void Print(const char* format, ...) PRINTF_ATTRIBUTE(1, 2) {
+ va_list args;
+ va_start(args, format);
+ VPrint(format, args);
+ va_end(args);
+ }
+
+ static void VPrint(const char* format, va_list args);
+
+ static void PrintErr(const char* format, ...) PRINTF_ATTRIBUTE(1, 2) {
+ va_list args;
+ va_start(args, format);
+ VPrintErr(format, args);
+ va_end(args);
+ }
+
+ static void VPrintErr(const char* format, va_list args);
+
+ DISALLOW_ALLOCATION();
+ DISALLOW_IMPLICIT_CONSTRUCTORS(Log);
+};
+
+#endif // BIN_LOG_H_
diff --git a/runtime/bin/log_android.cc b/runtime/bin/log_android.cc
new file mode 100644
index 0000000..0a6b552
--- /dev/null
+++ b/runtime/bin/log_android.cc
@@ -0,0 +1,20 @@
+// 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.
+
+#include "bin/log.h"
+
+#include <stdio.h>
+#include <android/log.h>
+
+// TODO(gram): We should be buffering the data and only outputting
+// it when we see a '\n'.
+
+void Log::VPrint(const char* format, va_list args) {
+ __android_log_vprint(ANDROID_LOG_INFO, "Dart", format, args);
+}
+
+void Log::VPrintErr(const char* format, va_list args) {
+ __android_log_vprint(ANDROID_LOG_ERROR, "Dart", format, args);
+}
+
diff --git a/runtime/bin/log_linux.cc b/runtime/bin/log_linux.cc
new file mode 100644
index 0000000..1b99c70
--- /dev/null
+++ b/runtime/bin/log_linux.cc
@@ -0,0 +1,18 @@
+// 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.
+
+#include "bin/log.h"
+
+#include <stdio.h>
+
+void Log::VPrint(const char* format, va_list args) {
+ vfprintf(stdout, format, args);
+ fflush(stdout);
+}
+
+void Log::VPrintErr(const char* format, va_list args) {
+ vfprintf(stderr, format, args);
+ fflush(stdout);
+}
+
diff --git a/runtime/bin/log_macos.cc b/runtime/bin/log_macos.cc
new file mode 100644
index 0000000..2f0d371
--- /dev/null
+++ b/runtime/bin/log_macos.cc
@@ -0,0 +1,17 @@
+// 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.
+
+#include "bin/log.h"
+
+#include <stdio.h>
+
+void Log::VPrint(const char* format, va_list args) {
+ vfprintf(stdout, format, args);
+ fflush(stdout);
+}
+
+void Log::VPrintErr(const char* format, va_list args) {
+ vfprintf(stderr, format, args);
+ fflush(stderr);
+}
diff --git a/runtime/bin/log_win.cc b/runtime/bin/log_win.cc
new file mode 100644
index 0000000..2f0d371
--- /dev/null
+++ b/runtime/bin/log_win.cc
@@ -0,0 +1,17 @@
+// 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.
+
+#include "bin/log.h"
+
+#include <stdio.h>
+
+void Log::VPrint(const char* format, va_list args) {
+ vfprintf(stdout, format, args);
+ fflush(stdout);
+}
+
+void Log::VPrintErr(const char* format, va_list args) {
+ vfprintf(stderr, format, args);
+ fflush(stderr);
+}
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 534f886..81c1373 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -17,6 +17,7 @@
#include "bin/extensions.h"
#include "bin/file.h"
#include "bin/isolate_data.h"
+#include "bin/log.h"
#include "bin/platform.h"
#include "bin/process.h"
#include "platform/globals.h"
@@ -142,7 +143,7 @@
}
}
if (debug_port == 0) {
- fprintf(stderr, "unrecognized --debug option syntax. "
+ Log::PrintErr("unrecognized --debug option syntax. "
"Use --debug[:<port number>]\n");
return false;
}
@@ -516,25 +517,25 @@
static void PrintVersion() {
- fprintf(stderr, "Dart VM version: %s\n", Dart_VersionString());
+ Log::PrintErr("Dart VM version: %s\n", Dart_VersionString());
}
static void PrintUsage() {
- fprintf(stderr,
+ Log::PrintErr(
"Usage: dart [<vm-flags>] <dart-script-file> [<dart-options>]\n"
"\n"
"Executes the Dart script passed as <dart-script-file>.\n"
"\n");
if (!has_verbose_option) {
- fprintf(stderr,
+ Log::PrintErr(
"Common options:\n"
"--checked Insert runtime type checks and enable assertions (checked mode).\n"
"--version Print the VM version.\n"
"--help Display this message (add --verbose for information about all\n"
" VM options).\n");
} else {
- fprintf(stderr,
+ Log::PrintErr(
"Supported options:\n"
"--checked\n"
" Insert runtime type checks and enable assertions (checked mode).\n"
@@ -626,8 +627,9 @@
static int ErrorExit(const char* format, ...) {
va_list arguments;
va_start(arguments, format);
- vfprintf(stderr, format, arguments);
+ Log::VPrintErr(format, arguments);
va_end(arguments);
+ fflush(stderr);
Dart_ExitScope();
Dart_ShutdownIsolate();
@@ -653,7 +655,7 @@
// Perform platform specific initialization.
if (!Platform::Initialize()) {
- fprintf(stderr, "Initialization failed\n");
+ Log::PrintErr("Initialization failed\n");
}
// On Windows, the argv strings are code page encoded and not
@@ -691,7 +693,9 @@
if (!Dart_Initialize(CreateIsolateAndSetup,
NULL,
ShutdownIsolate)) {
- return ErrorExit("VM initialization failed\n");
+ fprintf(stderr, "%s", "VM initialization failed\n");
+ fflush(stderr);
+ return kErrorExitCode;
}
DartUtils::SetOriginalWorkingDirectory();
@@ -710,7 +714,7 @@
"main",
new IsolateData(),
&error)) {
- fprintf(stderr, "%s\n", error);
+ Log::PrintErr("%s\n", error);
free(error);
delete [] isolate_name;
return kErrorExitCode; // Indicates we encountered an error.
diff --git a/runtime/bin/net/nss.gyp b/runtime/bin/net/nss.gyp
index ad5d888..64402b5 100644
--- a/runtime/bin/net/nss.gyp
+++ b/runtime/bin/net/nss.gyp
@@ -7,7 +7,7 @@
# BSD-style license that can be found in the LICENSE file.
# This file is a modified copy of Chromium's deps/third_party/nss/nss.gyp.
-# Revision 165464 (this should agree with "nss_rev" in DEPS).
+# Revision 169195 (this should agree with "nss_rev" in DEPS).
{
# Added by Dart. All Dart comments refer to the following block or line.
'includes': [
@@ -88,7 +88,7 @@
'conditions': [[ 'dart_io_support==1', {
'targets': [
{
- 'target_name': 'nspr_dart',
+ 'target_name': 'nspr_dart', # Added by Dart (the _dart postfix)
'product_name': 'crnspr',
'type': '<(component)',
# Changed by Dart: '<(nss_directory)/' added to all paths.
@@ -455,14 +455,14 @@
],
},
{
- 'target_name': 'nss_dart',
+ 'target_name': 'nss_dart', # Added by Dart (the _dart postfix)
'product_name': 'crnss',
'type': '<(component)',
'dependencies': [
- 'nss_static_dart',
+ 'nss_static_dart', # Added by Dart (the _dart postfix)
],
'export_dependent_settings': [
- 'nss_static_dart',
+ 'nss_static_dart', # Added by Dart (the _dart postfix)
],
'sources': [
# Ensure at least one object file is produced, so that MSVC does not
@@ -473,10 +473,10 @@
'conditions': [
['exclude_nss_root_certs==0', {
'dependencies': [
- 'nssckbi_dart',
+ 'nssckbi_dart', # Added by Dart (the _dart postfix)
],
'export_dependent_settings': [
- 'nssckbi_dart',
+ 'nssckbi_dart', # Added by Dart (the _dart postfix)
],
}],
['OS == "mac" and component == "shared_library"', {
@@ -506,7 +506,7 @@
#
# TODO(rsleevi): http://crbug.com/128134 - Break the circular dependency
# without requiring nssckbi to be built as a shared library.
- 'target_name': 'nssckbi_dart',
+ 'target_name': 'nssckbi_dart', # Added by Dart (the _dart postfix)
'product_name': 'crnssckbi',
'type': 'static_library',
# This target is an implementation detail - the public dependencies
@@ -554,10 +554,10 @@
'<(nss_directory)/mozilla/security/nss/lib/ckfw/wrap.c',
],
'dependencies': [
- 'nss_static_dart',
+ 'nss_static_dart', # Added by Dart (the _dart postfix)
],
'export_dependent_settings': [
- 'nss_static_dart',
+ 'nss_static_dart', # Added by Dart (the _dart postfix)
],
'include_dirs': [
'<(nss_directory)/mozilla/security/nss/lib/ckfw',
@@ -569,7 +569,7 @@
},
},
{
- 'target_name': 'nss_static_dart',
+ 'target_name': 'nss_static_dart', # Added by Dart (the _dart postfix)
'type': 'static_library',
# This target is an implementation detail - the public dependencies
# should be on 'nss'.
@@ -630,6 +630,7 @@
'<(nss_directory)/mozilla/security/nss/lib/cryptohi/keyt.h',
'<(nss_directory)/mozilla/security/nss/lib/cryptohi/keythi.h',
'<(nss_directory)/mozilla/security/nss/lib/cryptohi/sechash.c',
+ '<(nss_directory)/mozilla/security/nss/lib/cryptohi/sechash.h',
'<(nss_directory)/mozilla/security/nss/lib/cryptohi/seckey.c',
'<(nss_directory)/mozilla/security/nss/lib/cryptohi/secsign.c',
'<(nss_directory)/mozilla/security/nss/lib/cryptohi/secvfy.c',
@@ -678,7 +679,6 @@
'<(nss_directory)/mozilla/security/nss/lib/freebl/ecl/ecp_jm.c',
'<(nss_directory)/mozilla/security/nss/lib/freebl/ecl/ecp_mont.c',
'<(nss_directory)/mozilla/security/nss/lib/freebl/ecl/ec_naf.c',
- '<(nss_directory)/mozilla/security/nss/lib/freebl/hasht.h',
'<(nss_directory)/mozilla/security/nss/lib/freebl/jpake.c',
'<(nss_directory)/mozilla/security/nss/lib/freebl/md2.c',
'<(nss_directory)/mozilla/security/nss/lib/freebl/md5.c',
@@ -700,12 +700,12 @@
'<(nss_directory)/mozilla/security/nss/lib/freebl/mpi/mp_gf2m.h',
'<(nss_directory)/mozilla/security/nss/lib/freebl/mpi/primes.c',
'<(nss_directory)/mozilla/security/nss/lib/freebl/pqg.c',
+ '<(nss_directory)/mozilla/security/nss/lib/freebl/pqg.h',
'<(nss_directory)/mozilla/security/nss/lib/freebl/rawhash.c',
'<(nss_directory)/mozilla/security/nss/lib/freebl/rijndael.c',
'<(nss_directory)/mozilla/security/nss/lib/freebl/rijndael.h',
'<(nss_directory)/mozilla/security/nss/lib/freebl/rijndael32.tab',
'<(nss_directory)/mozilla/security/nss/lib/freebl/rsa.c',
- '<(nss_directory)/mozilla/security/nss/lib/freebl/sechash.h',
'<(nss_directory)/mozilla/security/nss/lib/freebl/secmpi.h',
'<(nss_directory)/mozilla/security/nss/lib/freebl/secrng.h',
'<(nss_directory)/mozilla/security/nss/lib/freebl/seed.c',
@@ -920,6 +920,7 @@
'<(nss_directory)/mozilla/security/nss/lib/pk11wrap/pk11util.c',
'<(nss_directory)/mozilla/security/nss/lib/pk11wrap/secmod.h',
'<(nss_directory)/mozilla/security/nss/lib/pk11wrap/secmodi.h',
+ '<(nss_directory)/mozilla/security/nss/lib/pk11wrap/secmodt.h',
'<(nss_directory)/mozilla/security/nss/lib/pk11wrap/secmodti.h',
'<(nss_directory)/mozilla/security/nss/lib/pk11wrap/secpkcs5.h',
'<(nss_directory)/mozilla/security/nss/lib/pkcs7/certread.c',
@@ -969,8 +970,6 @@
'<(nss_directory)/mozilla/security/nss/lib/softoken/lowpbe.c',
'<(nss_directory)/mozilla/security/nss/lib/softoken/lowpbe.h',
'<(nss_directory)/mozilla/security/nss/lib/softoken/padbuf.c',
- '<(nss_directory)/mozilla/security/nss/lib/softoken/pk11init.h',
- '<(nss_directory)/mozilla/security/nss/lib/softoken/pk11pars.h',
'<(nss_directory)/mozilla/security/nss/lib/softoken/pkcs11.c',
'<(nss_directory)/mozilla/security/nss/lib/softoken/pkcs11c.c',
'<(nss_directory)/mozilla/security/nss/lib/softoken/pkcs11i.h',
@@ -979,12 +978,10 @@
'<(nss_directory)/mozilla/security/nss/lib/softoken/rsawrapr.c',
'<(nss_directory)/mozilla/security/nss/lib/softoken/sdb.c',
'<(nss_directory)/mozilla/security/nss/lib/softoken/sdb.h',
- '<(nss_directory)/mozilla/security/nss/lib/softoken/secmodt.h',
'<(nss_directory)/mozilla/security/nss/lib/softoken/sftkdb.c',
'<(nss_directory)/mozilla/security/nss/lib/softoken/sftkdb.h',
'<(nss_directory)/mozilla/security/nss/lib/softoken/sftkdbt.h',
'<(nss_directory)/mozilla/security/nss/lib/softoken/sftkdbti.h',
- '<(nss_directory)/mozilla/security/nss/lib/softoken/sftkmod.c',
'<(nss_directory)/mozilla/security/nss/lib/softoken/sftkpars.c',
'<(nss_directory)/mozilla/security/nss/lib/softoken/sftkpars.h',
'<(nss_directory)/mozilla/security/nss/lib/softoken/sftkpwd.c',
@@ -1002,6 +999,7 @@
'<(nss_directory)/mozilla/security/nss/lib/util/dersubr.c',
'<(nss_directory)/mozilla/security/nss/lib/util/dertime.c',
'<(nss_directory)/mozilla/security/nss/lib/util/errstrs.c',
+ '<(nss_directory)/mozilla/security/nss/lib/util/hasht.h',
'<(nss_directory)/mozilla/security/nss/lib/util/nssb64.h',
'<(nss_directory)/mozilla/security/nss/lib/util/nssb64d.c',
'<(nss_directory)/mozilla/security/nss/lib/util/nssb64e.c',
@@ -1047,6 +1045,11 @@
'<(nss_directory)/mozilla/security/nss/lib/util/sectime.c',
'<(nss_directory)/mozilla/security/nss/lib/util/templates.c',
'<(nss_directory)/mozilla/security/nss/lib/util/utf8.c',
+ '<(nss_directory)/mozilla/security/nss/lib/util/utilmod.c',
+ '<(nss_directory)/mozilla/security/nss/lib/util/utilmodt.h',
+ '<(nss_directory)/mozilla/security/nss/lib/util/utilpars.c',
+ '<(nss_directory)/mozilla/security/nss/lib/util/utilpars.h',
+ '<(nss_directory)/mozilla/security/nss/lib/util/utilparst.h',
'<(nss_directory)/mozilla/security/nss/lib/util/utilrename.h',
],
'sources!': [
@@ -1059,11 +1062,11 @@
'<(nss_directory)/mozilla/security/nss/lib/pk11wrap/debug_module.c',
],
'dependencies': [
- 'nspr_dart',
- 'sqlite.gyp:sqlite_dart',
+ 'nspr_dart', # Added by Dart (the _dart postfix)
+ 'sqlite.gyp:sqlite_dart', # Changed by Dart prefix ../sqllite removed _dart postfix added.
],
'export_dependent_settings': [
- 'nspr_dart',
+ 'nspr_dart', # Added by Dart (the _dart postfix)
],
'defines': [
'MP_API_COMPATIBLE',
@@ -1148,6 +1151,9 @@
'defines': [
'NSS_DISABLE_LIBPKIX',
],
+ # Changed by Dart:
+ # nss_directory contains .., which is bad in a regular expression.
+ # So we use the partial match by dropping '^' from '^mozilla/...
'sources/': [
['exclude', 'mozilla/security/nss/lib/libpkix/'],
],
@@ -1155,6 +1161,9 @@
'<(nss_directory)/mozilla/security/nss/lib/certhigh/certvfypkix.c',
'<(nss_directory)/mozilla/security/nss/lib/certhigh/certvfypkixprint.c',
],
+ # Changed by Dart:
+ # nss_directory contains .., which is bad in a regular expression.
+ # So we use the partial match by dropping '^' from '^mozilla/...
'include_dirs/': [
['exclude', 'mozilla/security/nss/lib/libpkix/'],
],
@@ -1164,7 +1173,6 @@
['exclude', 'amd64'],
],
}],
- # Added by Dart.
['OS=="linux"', {
'defines': [
'XP_UNIX',
diff --git a/runtime/bin/net/sqlite.gyp b/runtime/bin/net/sqlite.gyp
index 543ca77..aa7ec81 100644
--- a/runtime/bin/net/sqlite.gyp
+++ b/runtime/bin/net/sqlite.gyp
@@ -7,7 +7,7 @@
# BSD-style license that can be found in the LICENSE file.
# This file is a modified copy of Chromium's src/third_party/sqlite/sqlite.gyp.
-# Revision 165464 (this should agree with "nss_rev" in DEPS).
+# Revision 169195 (this should agree with "nss_rev" in DEPS).
{
# Added by Dart. All Dart comments refer to the following block or line.
'includes': [
@@ -38,7 +38,7 @@
'conditions': [[ 'dart_io_support==1', {
'targets': [
{
- 'target_name': 'sqlite_dart',
+ 'target_name': 'sqlite_dart', # Added by Dart (the _dart postfix)
'conditions': [
[ 'chromeos==1' , {
'defines': [
@@ -184,12 +184,12 @@
['os_posix == 1 and OS != "mac" and OS != "ios" and OS != "android" and not use_system_sqlite', {
'targets': [
{
- 'target_name': 'sqlite_shell_dart',
+ 'target_name': 'sqlite_shell_dart', # Added by Dart (the _dart postfix)
'type': 'executable',
'dependencies': [
# Disabled by Dart.
# '../icu/icu.gyp:icuuc',
- 'sqlite_dart',
+ 'sqlite_dart', # Added by Dart (the _dart postfix)
],
'sources': [
'<(sqlite_directory)/src/src/shell.c',
diff --git a/runtime/bin/net/ssl.gyp b/runtime/bin/net/ssl.gyp
index cee5997..3798baa 100644
--- a/runtime/bin/net/ssl.gyp
+++ b/runtime/bin/net/ssl.gyp
@@ -7,7 +7,7 @@
# BSD-style license that can be found in the LICENSE file.
# This file is a modified copy of Chromium's src/net/third_party/nss/ssl.gyp.
-# Revision 165464 (this should agree with "nss_rev" in DEPS).
+# Revision 169195 (this should agree with "nss_rev" in DEPS).
{
# Conditions section for ssl-bodge (Compiling SSL on linux using system
# NSS and NSPR libraries) removed:
@@ -30,15 +30,14 @@
'conditions': [[ 'dart_io_support==1', {
'targets': [
{
- 'target_name': 'libssl_dart',
+ 'target_name': 'libssl_dart', # Added by Dart (the _dart postfix)
'type': 'static_library',
# Changed by Dart: '<(ssl_directory)/' added to all paths.
'sources': [
'<(ssl_directory)/ssl/authcert.c',
'<(ssl_directory)/ssl/cmpcert.c',
'<(ssl_directory)/ssl/derive.c',
- '<(ssl_directory)/ssl/dtls1con.c',
- '<(ssl_directory)/ssl/nsskea.c',
+ '<(ssl_directory)/ssl/dtlscon.c',
'<(ssl_directory)/ssl/os2_err.c',
'<(ssl_directory)/ssl/os2_err.h',
'<(ssl_directory)/ssl/preenc.h',
@@ -77,7 +76,9 @@
'<(ssl_directory)/ssl/unix_err.h',
'<(ssl_directory)/ssl/win32err.c',
'<(ssl_directory)/ssl/win32err.h',
+ # Changed by Dart: All files under '<(ssl_directory)/ssl/bodge' removed.
],
+ # Changed by Dart: '<(ssl_directory)/' added to all paths.
'sources!': [
'<(ssl_directory)/ssl/os2_err.c',
'<(ssl_directory)/ssl/os2_err.h',
@@ -92,14 +93,15 @@
'NO_NSPR_10_SUPPORT',
],
'dependencies': [
- 'zlib.gyp:zlib_dart',
+ # Changed by Dart.
+ 'zlib.gyp:zlib_dart', # Added by Dart (the _dart postfix)
# Dart: Start of copy of code from 'bodge' conditions section below.
- 'nss.gyp:nspr_dart',
- 'nss.gyp:nss_dart',
+ 'nss.gyp:nspr_dart', # Added by Dart (the _dart postfix)
+ 'nss.gyp:nss_dart', # Added by Dart (the _dart postfix)
],
'export_dependent_settings': [
- 'nss.gyp:nspr_dart',
- 'nss.gyp:nss_dart',
+ 'nss.gyp:nspr_dart', # Added by Dart (the _dart postfix)
+ 'nss.gyp:nss_dart', # Added by Dart (the _dart postfix)
],
'direct_dependent_settings': {
'include_dirs': [
diff --git a/runtime/bin/net/zlib.gyp b/runtime/bin/net/zlib.gyp
index e2dcd3f..99bca0f 100644
--- a/runtime/bin/net/zlib.gyp
+++ b/runtime/bin/net/zlib.gyp
@@ -7,7 +7,7 @@
# BSD-style license that can be found in the LICENSE file.
# This file is a modified copy of src/third_party/zlib/zlib.gyp from Chromium.
-# Revision 165464 (this should agree with "nss_rev" in DEPS).
+# Revision 169195 (this should agree with "nss_rev" in DEPS).
{
# Added by Dart. All Dart comments refer to the following block or line.
'includes': [
@@ -33,7 +33,7 @@
'conditions': [[ 'dart_io_support==1', {
'targets': [
{
- 'target_name': 'zlib_dart',
+ 'target_name': 'zlib_dart', # Added by Dart (the _dart postfix)
'type': 'static_library',
'conditions': [
['use_system_zlib==0', {
@@ -96,7 +96,7 @@
],
},
{
- 'target_name': 'minizip_dart',
+ 'target_name': 'minizip_dart', # Added by Dart (the _dart postfix)
'type': 'static_library',
'conditions': [
['use_system_minizip==0', {
diff --git a/runtime/bin/platform_win.cc b/runtime/bin/platform_win.cc
index 0af539d..750caa6 100644
--- a/runtime/bin/platform_win.cc
+++ b/runtime/bin/platform_win.cc
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
#include "bin/platform.h"
+#include "bin/log.h"
#include "bin/socket.h"
bool Platform::Initialize() {
@@ -73,7 +74,7 @@
NULL);
if (message_size == 0) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
- fprintf(stderr, "FormatMessage failed %d\n", GetLastError());
+ Log::PrintErr("FormatMessage failed %d\n", GetLastError());
}
snprintf(error, kBufferSize, "OS Error %d", error_code);
}
diff --git a/runtime/bin/process_android.cc b/runtime/bin/process_android.cc
index c834988..3d593e2 100644
--- a/runtime/bin/process_android.cc
+++ b/runtime/bin/process_android.cc
@@ -15,6 +15,7 @@
#include <unistd.h>
#include "bin/fdutils.h"
+#include "bin/log.h"
#include "bin/thread.h"
@@ -326,16 +327,15 @@
bool initialized = ExitCodeHandler::EnsureInitialized();
if (!initialized) {
SetChildOsErrorMessage(os_error_message, os_error_message_len);
- fprintf(stderr,
- "Error initializing exit code handler: %s\n",
- os_error_message);
+ Log::PrintErr("Error initializing exit code handler: %s\n",
+ os_error_message);
return errno;
}
result = TEMP_FAILURE_RETRY(pipe(read_in));
if (result < 0) {
SetChildOsErrorMessage(os_error_message, os_error_message_len);
- fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
+ Log::PrintErr("Error pipe creation failed: %s\n", os_error_message);
return errno;
}
@@ -344,7 +344,7 @@
SetChildOsErrorMessage(os_error_message, os_error_message_len);
TEMP_FAILURE_RETRY(close(read_in[0]));
TEMP_FAILURE_RETRY(close(read_in[1]));
- fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
+ Log::PrintErr("Error pipe creation failed: %s\n", os_error_message);
return errno;
}
@@ -355,7 +355,7 @@
TEMP_FAILURE_RETRY(close(read_in[1]));
TEMP_FAILURE_RETRY(close(read_err[0]));
TEMP_FAILURE_RETRY(close(read_err[1]));
- fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
+ Log::PrintErr("Error pipe creation failed: %s\n", os_error_message);
return errno;
}
@@ -368,7 +368,7 @@
TEMP_FAILURE_RETRY(close(read_err[1]));
TEMP_FAILURE_RETRY(close(write_out[0]));
TEMP_FAILURE_RETRY(close(write_out[1]));
- fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
+ Log::PrintErr("Error pipe creation failed: %s\n", os_error_message);
return errno;
}
@@ -387,7 +387,7 @@
TEMP_FAILURE_RETRY(close(write_out[1]));
TEMP_FAILURE_RETRY(close(exec_control[0]));
TEMP_FAILURE_RETRY(close(exec_control[1]));
- fprintf(stderr, "fcntl failed: %s\n", os_error_message);
+ Log::PrintErr("fcntl failed: %s\n", os_error_message);
return errno;
}
@@ -488,7 +488,7 @@
TEMP_FAILURE_RETRY(close(read_err[1]));
TEMP_FAILURE_RETRY(close(write_out[0]));
TEMP_FAILURE_RETRY(close(write_out[1]));
- fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
+ Log::PrintErr("Error pipe creation failed: %s\n", os_error_message);
return errno;
}
diff --git a/runtime/bin/process_linux.cc b/runtime/bin/process_linux.cc
index ffc5c88..bd4ed87 100644
--- a/runtime/bin/process_linux.cc
+++ b/runtime/bin/process_linux.cc
@@ -15,6 +15,7 @@
#include <unistd.h>
#include "bin/fdutils.h"
+#include "bin/log.h"
#include "bin/thread.h"
extern char **environ;
@@ -327,7 +328,7 @@
bool initialized = ExitCodeHandler::EnsureInitialized();
if (!initialized) {
SetChildOsErrorMessage(os_error_message, os_error_message_len);
- fprintf(stderr,
+ Log::PrintErr(
"Error initializing exit code handler: %s\n",
os_error_message);
return errno;
@@ -336,7 +337,7 @@
result = TEMP_FAILURE_RETRY(pipe(read_in));
if (result < 0) {
SetChildOsErrorMessage(os_error_message, os_error_message_len);
- fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
+ Log::PrintErr("Error pipe creation failed: %s\n", os_error_message);
return errno;
}
@@ -345,7 +346,7 @@
SetChildOsErrorMessage(os_error_message, os_error_message_len);
TEMP_FAILURE_RETRY(close(read_in[0]));
TEMP_FAILURE_RETRY(close(read_in[1]));
- fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
+ Log::PrintErr("Error pipe creation failed: %s\n", os_error_message);
return errno;
}
@@ -356,7 +357,7 @@
TEMP_FAILURE_RETRY(close(read_in[1]));
TEMP_FAILURE_RETRY(close(read_err[0]));
TEMP_FAILURE_RETRY(close(read_err[1]));
- fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
+ Log::PrintErr("Error pipe creation failed: %s\n", os_error_message);
return errno;
}
@@ -369,7 +370,7 @@
TEMP_FAILURE_RETRY(close(read_err[1]));
TEMP_FAILURE_RETRY(close(write_out[0]));
TEMP_FAILURE_RETRY(close(write_out[1]));
- fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
+ Log::PrintErr("Error pipe creation failed: %s\n", os_error_message);
return errno;
}
@@ -388,7 +389,7 @@
TEMP_FAILURE_RETRY(close(write_out[1]));
TEMP_FAILURE_RETRY(close(exec_control[0]));
TEMP_FAILURE_RETRY(close(exec_control[1]));
- fprintf(stderr, "fcntl failed: %s\n", os_error_message);
+ Log::PrintErr("fcntl failed: %s\n", os_error_message);
return errno;
}
@@ -487,7 +488,7 @@
TEMP_FAILURE_RETRY(close(read_err[1]));
TEMP_FAILURE_RETRY(close(write_out[0]));
TEMP_FAILURE_RETRY(close(write_out[1]));
- fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
+ Log::PrintErr("Error pipe creation failed: %s\n", os_error_message);
return errno;
}
diff --git a/runtime/bin/process_macos.cc b/runtime/bin/process_macos.cc
index 11aac9f..aa15940 100644
--- a/runtime/bin/process_macos.cc
+++ b/runtime/bin/process_macos.cc
@@ -14,6 +14,7 @@
#include <unistd.h>
#include "bin/fdutils.h"
+#include "bin/log.h"
#include "bin/thread.h"
extern char **environ;
@@ -326,16 +327,15 @@
bool initialized = ExitCodeHandler::EnsureInitialized();
if (!initialized) {
SetChildOsErrorMessage(os_error_message, os_error_message_len);
- fprintf(stderr,
- "Error initializing exit code handler: %s\n",
- os_error_message);
+ Log::PrintErr("Error initializing exit code handler: %s\n",
+ os_error_message);
return errno;
}
result = TEMP_FAILURE_RETRY(pipe(read_in));
if (result < 0) {
SetChildOsErrorMessage(os_error_message, os_error_message_len);
- fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
+ Log::PrintErr("Error pipe creation failed: %s\n", os_error_message);
return errno;
}
@@ -344,7 +344,7 @@
SetChildOsErrorMessage(os_error_message, os_error_message_len);
TEMP_FAILURE_RETRY(close(read_in[0]));
TEMP_FAILURE_RETRY(close(read_in[1]));
- fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
+ Log::PrintErr("Error pipe creation failed: %s\n", os_error_message);
return errno;
}
@@ -355,7 +355,7 @@
TEMP_FAILURE_RETRY(close(read_in[1]));
TEMP_FAILURE_RETRY(close(read_err[0]));
TEMP_FAILURE_RETRY(close(read_err[1]));
- fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
+ Log::PrintErr("Error pipe creation failed: %s\n", os_error_message);
return errno;
}
@@ -368,7 +368,7 @@
TEMP_FAILURE_RETRY(close(read_err[1]));
TEMP_FAILURE_RETRY(close(write_out[0]));
TEMP_FAILURE_RETRY(close(write_out[1]));
- fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
+ Log::PrintErr("Error pipe creation failed: %s\n", os_error_message);
return errno;
}
@@ -387,7 +387,7 @@
TEMP_FAILURE_RETRY(close(write_out[1]));
TEMP_FAILURE_RETRY(close(exec_control[0]));
TEMP_FAILURE_RETRY(close(exec_control[1]));
- fprintf(stderr, "fcntl failed: %s\n", os_error_message);
+ Log::PrintErr("fcntl failed: %s\n", os_error_message);
return errno;
}
@@ -486,7 +486,7 @@
TEMP_FAILURE_RETRY(close(read_err[1]));
TEMP_FAILURE_RETRY(close(write_out[0]));
TEMP_FAILURE_RETRY(close(write_out[1]));
- fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
+ Log::PrintErr("Error pipe creation failed: %s\n", os_error_message);
return errno;
}
diff --git a/runtime/bin/process_win.cc b/runtime/bin/process_win.cc
index 3094176..0a9eb52 100644
--- a/runtime/bin/process_win.cc
+++ b/runtime/bin/process_win.cc
@@ -7,6 +7,7 @@
#include "bin/builtin.h"
#include "bin/process.h"
#include "bin/eventhandler.h"
+#include "bin/log.h"
#include "bin/thread.h"
#include "bin/utils.h"
#include "platform/globals.h"
@@ -221,7 +222,7 @@
NULL);
if (handles[kWriteHandle] == INVALID_HANDLE_VALUE) {
- fprintf(stderr, "CreateNamedPipe failed %d\n", GetLastError());
+ Log::PrintErr("CreateNamedPipe failed %d\n", GetLastError());
return false;
}
@@ -234,7 +235,7 @@
FILE_READ_ATTRIBUTES | FILE_FLAG_OVERLAPPED,
NULL);
if (handles[kReadHandle] == INVALID_HANDLE_VALUE) {
- fprintf(stderr, "CreateFile failed %d\n", GetLastError());
+ Log::PrintErr("CreateFile failed %d\n", GetLastError());
return false;
}
} else {
@@ -250,7 +251,7 @@
NULL);
if (handles[kReadHandle] == INVALID_HANDLE_VALUE) {
- fprintf(stderr, "CreateNamedPipe failed %d\n", GetLastError());
+ Log::PrintErr("CreateNamedPipe failed %d\n", GetLastError());
return false;
}
@@ -263,7 +264,7 @@
FILE_WRITE_ATTRIBUTES | FILE_FLAG_OVERLAPPED,
NULL);
if (handles[kWriteHandle] == INVALID_HANDLE_VALUE) {
- fprintf(stderr, "CreateFile failed %d\n", GetLastError());
+ Log::PrintErr("CreateFile failed %d\n", GetLastError());
return false;
}
}
@@ -275,7 +276,7 @@
for (int i = kReadHandle; i < kWriteHandle; i++) {
if (handles[i] != INVALID_HANDLE_VALUE) {
if (!CloseHandle(handles[i])) {
- fprintf(stderr, "CloseHandle failed %d\n", GetLastError());
+ Log::PrintErr("CloseHandle failed %d\n", GetLastError());
}
handles[i] = INVALID_HANDLE_VALUE;
}
@@ -306,7 +307,7 @@
NULL);
if (message_size == 0) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
- fprintf(stderr, "FormatMessage failed %d\n", GetLastError());
+ Log::PrintErr("FormatMessage failed %d\n", GetLastError());
}
snprintf(os_error_message, os_error_message_len, "OS Error %d", error_code);
}
@@ -338,14 +339,14 @@
UUID uuid;
RPC_STATUS status = UuidCreateSequential(&uuid);
if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) {
- fprintf(stderr, "UuidCreateSequential failed %d\n", status);
+ Log::PrintErr("UuidCreateSequential failed %d\n", status);
SetOsErrorMessage(os_error_message, os_error_message_len);
return status;
}
RPC_CSTR uuid_string;
status = UuidToString(&uuid, &uuid_string);
if (status != RPC_S_OK) {
- fprintf(stderr, "UuidToString failed %d\n", status);
+ Log::PrintErr("UuidToString failed %d\n", status);
SetOsErrorMessage(os_error_message, os_error_message_len);
return status;
}
@@ -357,7 +358,7 @@
}
status = RpcStringFree(&uuid_string);
if (status != RPC_S_OK) {
- fprintf(stderr, "RpcStringFree failed %d\n", status);
+ Log::PrintErr("RpcStringFree failed %d\n", status);
SetOsErrorMessage(os_error_message, os_error_message_len);
return status;
}
diff --git a/runtime/bin/run_vm_tests.cc b/runtime/bin/run_vm_tests.cc
index f539d31..d73b046 100644
--- a/runtime/bin/run_vm_tests.cc
+++ b/runtime/bin/run_vm_tests.cc
@@ -138,8 +138,8 @@
bool set_vm_flags_success = Flags::ProcessCommandLineFlags(dart_argc,
dart_argv);
ASSERT(set_vm_flags_success);
- bool init_success = Dart::InitOnce(NULL, NULL, NULL);
- ASSERT(init_success);
+ const char* err_msg = Dart::InitOnce(NULL, NULL, NULL);
+ ASSERT(err_msg == NULL);
// Apply the filter to all registered tests.
TestCaseBase::RunAll();
// Apply the filter to all registered benchmarks.
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc
new file mode 100644
index 0000000..f297aed
--- /dev/null
+++ b/runtime/bin/secure_socket.cc
@@ -0,0 +1,484 @@
+// 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.
+
+#include "bin/secure_socket.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <nss.h>
+#include <pk11pub.h>
+#include <prerror.h>
+#include <prinit.h>
+#include <prnetdb.h>
+#include <ssl.h>
+#include <sslproto.h>
+
+#include "bin/builtin.h"
+#include "bin/dartutils.h"
+#include "bin/net/nss_memio.h"
+#include "bin/thread.h"
+#include "bin/utils.h"
+#include "platform/utils.h"
+
+#include "include/dart_api.h"
+
+bool SSLFilter::library_initialized_ = false;
+dart::Mutex SSLFilter::mutex_; // To protect library initialization.
+// The password is needed when creating secure server sockets. It can
+// be null if only secure client sockets are used.
+const char* SSLFilter::password_ = NULL;
+
+static const int kSSLFilterNativeFieldIndex = 0;
+
+static SSLFilter* GetFilter(Dart_NativeArguments args) {
+ SSLFilter* filter;
+ Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
+ ASSERT(Dart_IsInstance(dart_this));
+ ThrowIfError(Dart_GetNativeInstanceField(
+ dart_this,
+ kSSLFilterNativeFieldIndex,
+ reinterpret_cast<intptr_t*>(&filter)));
+ return filter;
+}
+
+
+static void SetFilter(Dart_NativeArguments args, SSLFilter* filter) {
+ Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
+ ASSERT(Dart_IsInstance(dart_this));
+ ThrowIfError(Dart_SetNativeInstanceField(
+ dart_this,
+ kSSLFilterNativeFieldIndex,
+ reinterpret_cast<intptr_t>(filter)));
+}
+
+
+void FUNCTION_NAME(SecureSocket_Init)(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
+ SSLFilter* filter = new SSLFilter;
+ SetFilter(args, filter);
+ filter->Init(dart_this);
+ Dart_ExitScope();
+}
+
+
+void FUNCTION_NAME(SecureSocket_Connect)(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_Handle host_name_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
+ Dart_Handle port_object = ThrowIfError(Dart_GetNativeArgument(args, 2));
+ Dart_Handle is_server_object = ThrowIfError(Dart_GetNativeArgument(args, 3));
+ Dart_Handle certificate_name_object =
+ ThrowIfError(Dart_GetNativeArgument(args, 4));
+
+ const char* host_name = NULL;
+ // TODO(whesse): Is truncating a Dart string containing \0 what we want?
+ ThrowIfError(Dart_StringToCString(host_name_object, &host_name));
+
+ int64_t port;
+ if (!DartUtils::GetInt64Value(port_object, &port) ||
+ port < 0 || port > 65535) {
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Illegal port parameter in _SSLFilter.connect"));
+ }
+
+ if (!Dart_IsBoolean(is_server_object)) {
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Illegal is_server parameter in _SSLFilter.connect"));
+ }
+ bool is_server = DartUtils::GetBooleanValue(is_server_object);
+
+ const char* certificate_name = NULL;
+ // If this is a server connection, get the certificate to connect with.
+ // TODO(whesse): Use this parameter for a client certificate as well.
+ if (is_server) {
+ if (!Dart_IsString(certificate_name_object)) {
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Non-String certificate parameter in _SSLFilter.connect"));
+ }
+ ThrowIfError(Dart_StringToCString(certificate_name_object,
+ &certificate_name));
+ }
+
+ GetFilter(args)->Connect(host_name,
+ static_cast<int>(port),
+ is_server,
+ certificate_name);
+ Dart_ExitScope();
+}
+
+
+void FUNCTION_NAME(SecureSocket_Destroy)(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ SSLFilter* filter = GetFilter(args);
+ SetFilter(args, NULL);
+ filter->Destroy();
+ delete filter;
+ Dart_ExitScope();
+}
+
+
+void FUNCTION_NAME(SecureSocket_Handshake)(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ GetFilter(args)->Handshake();
+ Dart_ExitScope();
+}
+
+
+void FUNCTION_NAME(SecureSocket_RegisterHandshakeCompleteCallback)(
+ Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_Handle handshake_complete =
+ ThrowIfError(Dart_GetNativeArgument(args, 1));
+ if (!Dart_IsClosure(handshake_complete)) {
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Illegal argument to RegisterHandshakeCompleteCallback"));
+ }
+ GetFilter(args)->RegisterHandshakeCompleteCallback(handshake_complete);
+ Dart_ExitScope();
+}
+
+
+void FUNCTION_NAME(SecureSocket_ProcessBuffer)(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_Handle buffer_id_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
+ int64_t buffer_id = DartUtils::GetIntegerValue(buffer_id_object);
+ if (buffer_id < 0 || buffer_id >= SSLFilter::kNumBuffers) {
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Illegal argument to ProcessBuffer"));
+ }
+
+ intptr_t bytes_read =
+ GetFilter(args)->ProcessBuffer(static_cast<int>(buffer_id));
+ Dart_SetReturnValue(args, Dart_NewInteger(bytes_read));
+ Dart_ExitScope();
+}
+
+
+void FUNCTION_NAME(SecureSocket_SetCertificateDatabase)
+ (Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_Handle certificate_database_object =
+ ThrowIfError(Dart_GetNativeArgument(args, 0));
+ // Check that the type is string, and get the UTF-8 C string value from it.
+ const char* certificate_database = NULL;
+ if (Dart_IsString(certificate_database_object)) {
+ ThrowIfError(Dart_StringToCString(certificate_database_object,
+ &certificate_database));
+ } else {
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Non-String certificate directory argument to SetCertificateDatabase"));
+ }
+
+ Dart_Handle password_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
+ // Check that the type is string or null,
+ // and get the UTF-8 C string value from it.
+ const char* password = NULL;
+ if (Dart_IsString(password_object)) {
+ ThrowIfError(Dart_StringToCString(password_object, &password));
+ } else if (Dart_IsNull(password_object)) {
+ // Pass the empty string as the password.
+ password = "";
+ } else {
+ Dart_ThrowException(DartUtils::NewDartArgumentError(
+ "Password argument to SetCertificateDatabase is not a String or null"));
+ }
+
+ SSLFilter::InitializeLibrary(certificate_database, password);
+ Dart_ExitScope();
+}
+
+
+void SSLFilter::Init(Dart_Handle dart_this) {
+ string_start_ = ThrowIfError(
+ Dart_NewPersistentHandle(DartUtils::NewString("start")));
+ string_length_ = ThrowIfError(
+ Dart_NewPersistentHandle(DartUtils::NewString("length")));
+
+ InitializeBuffers(dart_this);
+ filter_ = memio_CreateIOLayer(kMemioBufferSize);
+}
+
+
+void SSLFilter::InitializeBuffers(Dart_Handle dart_this) {
+ // Create SSLFilter buffers as ExternalUint8Array objects.
+ Dart_Handle dart_buffers_object = ThrowIfError(
+ Dart_GetField(dart_this, DartUtils::NewString("buffers")));
+ Dart_Handle dart_buffer_object =
+ Dart_ListGetAt(dart_buffers_object, kReadPlaintext);
+ Dart_Handle external_buffer_class =
+ Dart_InstanceGetClass(dart_buffer_object);
+ Dart_Handle dart_buffer_size = ThrowIfError(
+ Dart_GetField(external_buffer_class, DartUtils::NewString("SIZE")));
+ buffer_size_ = DartUtils::GetIntegerValue(dart_buffer_size);
+ if (buffer_size_ <= 0 || buffer_size_ > 1024 * 1024) {
+ Dart_ThrowException(
+ DartUtils::NewString("Invalid buffer size in _ExternalBuffer"));
+ }
+
+ Dart_Handle data_identifier = DartUtils::NewString("data");
+ for (int i = 0; i < kNumBuffers; ++i) {
+ dart_buffer_objects_[i] = ThrowIfError(
+ Dart_NewPersistentHandle(Dart_ListGetAt(dart_buffers_object, i)));
+ buffers_[i] = new uint8_t[buffer_size_];
+ Dart_Handle data = ThrowIfError(
+ Dart_NewExternalByteArray(buffers_[i], buffer_size_, NULL, NULL));
+ ThrowIfError(Dart_SetField(dart_buffer_objects_[i],
+ data_identifier,
+ data));
+ }
+}
+
+
+void SSLFilter::RegisterHandshakeCompleteCallback(Dart_Handle complete) {
+ ASSERT(NULL == handshake_complete_);
+ handshake_complete_ = ThrowIfError(Dart_NewPersistentHandle(complete));
+}
+
+
+void SSLFilter::InitializeLibrary(const char* certificate_database,
+ const char* password) {
+ MutexLocker locker(&mutex_);
+ if (!library_initialized_) {
+ library_initialized_ = true;
+ password_ = strdup(password); // This one copy persists until Dart exits.
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+ // TODO(whesse): Verify there are no UTF-8 issues here.
+ SECStatus status = NSS_Init(certificate_database);
+ if (status != SECSuccess) {
+ ThrowPRException("Unsuccessful NSS_Init call.");
+ }
+
+ status = NSS_SetDomesticPolicy();
+ if (status != SECSuccess) {
+ ThrowPRException("Unsuccessful NSS_SetDomesticPolicy call.");
+ }
+ // Enable TLS, as well as SSL3 and SSL2.
+ status = SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE);
+ if (status != SECSuccess) {
+ ThrowPRException("Unsuccessful SSL_OptionSetDefault enable TLS call.");
+ }
+ } else {
+ ThrowException("Called SSLFilter::InitializeLibrary more than once");
+ }
+}
+
+char* PasswordCallback(PK11SlotInfo* slot, PRBool retry, void* arg) {
+ if (!retry) {
+ return PL_strdup(static_cast<char*>(arg)); // Freed by NSS internals.
+ }
+ return NULL;
+}
+
+void SSLFilter::Connect(const char* host_name,
+ int port,
+ bool is_server,
+ const char* certificate_name) {
+ is_server_ = is_server;
+ if (in_handshake_) {
+ ThrowException("Connect called while already in handshake state.");
+ }
+
+ filter_ = SSL_ImportFD(NULL, filter_);
+ if (filter_ == NULL) {
+ ThrowPRException("Unsuccessful SSL_ImportFD call");
+ }
+
+ SECStatus status;
+ if (is_server) {
+ PK11_SetPasswordFunc(PasswordCallback);
+ CERTCertDBHandle* certificate_database = CERT_GetDefaultCertDB();
+ if (certificate_database == NULL) {
+ ThrowPRException("Certificate database cannot be loaded");
+ }
+ CERTCertificate* certificate = CERT_FindCertByNameString(
+ certificate_database,
+ const_cast<char*>(certificate_name));
+ if (certificate == NULL) {
+ ThrowPRException("Cannot find server certificate by name");
+ }
+ SECKEYPrivateKey* key = PK11_FindKeyByAnyCert(
+ certificate,
+ static_cast<void*>(const_cast<char*>(password_)));
+ if (key == NULL) {
+ if (PR_GetError() == -8177) {
+ ThrowPRException("Certificate database password incorrect");
+ } else {
+ ThrowPRException("Unsuccessful PK11_FindKeyByAnyCert call."
+ " Cannot find private key for certificate");
+ }
+ }
+ // kt_rsa (key type RSA) is an enum constant from the NSS libraries.
+ // TODO(whesse): Allow different key types.
+ status = SSL_ConfigSecureServer(filter_, certificate, key, kt_rsa);
+ if (status != SECSuccess) {
+ ThrowPRException("Unsuccessful SSL_ConfigSecureServer call");
+ }
+ } else { // Client.
+ if (SSL_SetURL(filter_, host_name) == -1) {
+ ThrowPRException("Unsuccessful SetURL call");
+ }
+ }
+
+ PRBool as_server = is_server ? PR_TRUE : PR_FALSE; // Convert bool to PRBool.
+ status = SSL_ResetHandshake(filter_, as_server);
+ if (status != SECSuccess) {
+ ThrowPRException("Unsuccessful SSL_ResetHandshake call");
+ }
+
+ // SetPeerAddress
+ PRNetAddr host_address;
+ char host_entry_buffer[PR_NETDB_BUF_SIZE];
+ PRHostEnt host_entry;
+ PRStatus rv = PR_GetHostByName(host_name, host_entry_buffer,
+ PR_NETDB_BUF_SIZE, &host_entry);
+ if (rv != PR_SUCCESS) {
+ ThrowPRException("Unsuccessful PR_GetHostByName call");
+ }
+
+ int index = PR_EnumerateHostEnt(0, &host_entry, port, &host_address);
+ if (index == -1 || index == 0) {
+ ThrowPRException("Unsuccessful PR_EnumerateHostEnt call");
+ }
+ memio_SetPeerName(filter_, &host_address);
+}
+
+
+void SSLFilter::Handshake() {
+ SECStatus status = SSL_ForceHandshake(filter_);
+ if (status == SECSuccess) {
+ if (in_handshake_) {
+ ThrowIfError(Dart_InvokeClosure(handshake_complete_, 0, NULL));
+ in_handshake_ = false;
+ }
+ } else {
+ PRErrorCode error = PR_GetError();
+ if (error == PR_WOULD_BLOCK_ERROR) {
+ if (!in_handshake_) {
+ in_handshake_ = true;
+ }
+ } else {
+ if (is_server_) {
+ ThrowPRException("Unexpected handshake error in server");
+ } else {
+ ThrowPRException("Unexpected handshake error in client");
+ }
+ }
+ }
+}
+
+
+void SSLFilter::Destroy() {
+ for (int i = 0; i < kNumBuffers; ++i) {
+ Dart_DeletePersistentHandle(dart_buffer_objects_[i]);
+ delete[] buffers_[i];
+ }
+ Dart_DeletePersistentHandle(string_start_);
+ Dart_DeletePersistentHandle(string_length_);
+ Dart_DeletePersistentHandle(handshake_complete_);
+ // TODO(whesse): Free NSS objects here.
+}
+
+
+intptr_t SSLFilter::ProcessBuffer(int buffer_index) {
+ Dart_Handle buffer_object = dart_buffer_objects_[buffer_index];
+ Dart_Handle start_object = ThrowIfError(
+ Dart_GetField(buffer_object, string_start_));
+ Dart_Handle length_object = ThrowIfError(
+ Dart_GetField(buffer_object, string_length_));
+ int64_t unsafe_start = DartUtils::GetIntegerValue(start_object);
+ int64_t unsafe_length = DartUtils::GetIntegerValue(length_object);
+ ASSERT(unsafe_start >= 0);
+ ASSERT(unsafe_start < buffer_size_);
+ ASSERT(unsafe_length >= 0);
+ ASSERT(unsafe_length <= buffer_size_);
+ intptr_t start = static_cast<intptr_t>(unsafe_start);
+ intptr_t length = static_cast<intptr_t>(unsafe_length);
+ uint8_t* buffer = buffers_[buffer_index];
+
+ int bytes_processed = 0;
+ switch (buffer_index) {
+ case kReadPlaintext: {
+ int bytes_free = buffer_size_ - start - length;
+ bytes_processed = PR_Read(filter_,
+ buffer + start + length,
+ bytes_free);
+ if (bytes_processed < 0) {
+ ASSERT(bytes_processed == -1);
+ // TODO(whesse): Handle unexpected errors here.
+ PRErrorCode pr_error = PR_GetError();
+ if (PR_WOULD_BLOCK_ERROR != pr_error) {
+ ThrowPRException("Error reading plaintext from SSLFilter");
+ }
+ bytes_processed = 0;
+ }
+ break;
+ }
+
+ case kWriteEncrypted: {
+ const uint8_t* buf1;
+ const uint8_t* buf2;
+ unsigned int len1;
+ unsigned int len2;
+ int bytes_free = buffer_size_ - start - length;
+ memio_Private* secret = memio_GetSecret(filter_);
+ memio_GetWriteParams(secret, &buf1, &len1, &buf2, &len2);
+ int bytes_to_send =
+ dart::Utils::Minimum(len1, static_cast<unsigned>(bytes_free));
+ if (bytes_to_send > 0) {
+ memmove(buffer + start + length, buf1, bytes_to_send);
+ bytes_processed = bytes_to_send;
+ }
+ bytes_to_send = dart::Utils::Minimum(len2,
+ static_cast<unsigned>(bytes_free - bytes_processed));
+ if (bytes_to_send > 0) {
+ memmove(buffer + start + length + bytes_processed, buf2,
+ bytes_to_send);
+ bytes_processed += bytes_to_send;
+ }
+ if (bytes_processed > 0) {
+ memio_PutWriteResult(secret, bytes_processed);
+ }
+ break;
+ }
+
+ case kReadEncrypted: {
+ if (length > 0) {
+ bytes_processed = length;
+ memio_Private* secret = memio_GetSecret(filter_);
+ uint8_t* filter_buf;
+ int free_bytes = memio_GetReadParams(secret, &filter_buf);
+ if (free_bytes < bytes_processed) bytes_processed = free_bytes;
+ memmove(filter_buf,
+ buffer + start,
+ bytes_processed);
+ memio_PutReadResult(secret, bytes_processed);
+ }
+ break;
+ }
+
+ case kWritePlaintext: {
+ if (length > 0) {
+ bytes_processed = PR_Write(filter_,
+ buffer + start,
+ length);
+ }
+
+ if (bytes_processed < 0) {
+ ASSERT(bytes_processed == -1);
+ // TODO(whesse): Handle unexpected errors here.
+ PRErrorCode pr_error = PR_GetError();
+ if (PR_WOULD_BLOCK_ERROR != pr_error) {
+ ThrowPRException("Error reading plaintext from SSLFilter");
+ }
+ bytes_processed = 0;
+ }
+ break;
+ }
+ }
+ return bytes_processed;
+}
diff --git a/runtime/bin/tls_socket.h b/runtime/bin/secure_socket.h
similarity index 77%
rename from runtime/bin/tls_socket.h
rename to runtime/bin/secure_socket.h
index fc39b70..22ef7dc 100644
--- a/runtime/bin/tls_socket.h
+++ b/runtime/bin/secure_socket.h
@@ -2,8 +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.
-#ifndef BIN_TLS_SOCKET_H_
-#define BIN_TLS_SOCKET_H_
+#ifndef BIN_SECURE_SOCKET_H_
+#define BIN_SECURE_SOCKET_H_
#include <stdlib.h>
#include <string.h>
@@ -44,15 +44,15 @@
}
/*
- * TlsFilter encapsulates the NSS SSL(TLS) code in a filter, that communicates
- * with the containing _TlsFilterImpl Dart object through four shared
+ * SSLFilter encapsulates the NSS SSL(TLS) code in a filter, that communicates
+ * with the containing _SecureFilterImpl Dart object through four shared
* ExternalByteArray buffers, for reading and writing plaintext, and
* reading and writing encrypted text. The filter handles handshaking
* and certificate verification.
*/
-class TlsFilter {
+class SSLFilter {
public:
- // These enums must agree with those in sdk/lib/io/tls_socket.dart.
+ // These enums must agree with those in sdk/lib/io/secure_socket.dart.
enum BufferIndex {
kReadPlaintext,
kWritePlaintext,
@@ -61,26 +61,30 @@
kNumBuffers
};
- TlsFilter()
+ SSLFilter()
: string_start_(NULL),
string_length_(NULL),
handshake_complete_(NULL),
in_handshake_(false),
- memio_(NULL) { }
+ filter_(NULL) { }
void Init(Dart_Handle dart_this);
- void Connect(const char* host, int port);
+ void Connect(const char* host,
+ int port,
+ bool is_server,
+ const char* certificate_name);
void Destroy();
- void DestroyPlatformIndependent();
void Handshake();
void RegisterHandshakeCompleteCallback(Dart_Handle handshake_complete);
- static void InitializeLibrary(const char* pkcert_directory);
+ static void InitializeLibrary(const char* certificate_database,
+ const char* password);
intptr_t ProcessBuffer(int bufferIndex);
private:
static const int kMemioBufferSize = 20 * KB;
static bool library_initialized_;
+ static const char* password_;
static dart::Mutex mutex_; // To protect library initialization.
uint8_t* buffers_[kNumBuffers];
@@ -90,12 +94,13 @@
Dart_Handle dart_buffer_objects_[kNumBuffers];
Dart_Handle handshake_complete_;
bool in_handshake_;
- PRFileDesc* memio_;
+ bool is_server_;
+ PRFileDesc* filter_;
void InitializeBuffers(Dart_Handle dart_this);
void InitializePlatformData();
- DISALLOW_COPY_AND_ASSIGN(TlsFilter);
+ DISALLOW_COPY_AND_ASSIGN(SSLFilter);
};
-#endif // BIN_TLS_SOCKET_H_
+#endif // BIN_SECURE_SOCKET_H_
diff --git a/runtime/bin/secure_socket_patch.dart b/runtime/bin/secure_socket_patch.dart
new file mode 100644
index 0000000..34edc7e
--- /dev/null
+++ b/runtime/bin/secure_socket_patch.dart
@@ -0,0 +1,58 @@
+// 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.
+
+patch class SecureSocket {
+ /* patch */ static void setCertificateDatabase(String certificateDatabase,
+ [String password])
+ native "SecureSocket_SetCertificateDatabase";
+}
+
+
+patch class _SecureFilter {
+ /* patch */ factory _SecureFilter() => new _SecureFilterImpl();
+}
+
+
+/**
+ * _SecureFilterImpl wraps a filter that encrypts and decrypts data travelling
+ * over an encrypted socket. The filter also handles the handshaking
+ * and certificate verification.
+ *
+ * The filter exposes its input and output buffers as Dart objects that
+ * are backed by an external C array of bytes, so that both Dart code and
+ * native code can access the same data.
+ */
+class _SecureFilterImpl
+ extends NativeFieldWrapperClass1
+ implements _SecureFilter {
+ _SecureFilterImpl() {
+ buffers = new List<_ExternalBuffer>(_SecureSocket.NUM_BUFFERS);
+ for (int i = 0; i < _SecureSocket.NUM_BUFFERS; ++i) {
+ buffers[i] = new _ExternalBuffer();
+ }
+ }
+
+ void connect(String hostName,
+ int port,
+ bool is_server,
+ String certificate_name) native "SecureSocket_Connect";
+
+ void destroy() {
+ buffers = null;
+ _destroy();
+ }
+
+ void _destroy() native "SecureSocket_Destroy";
+
+ void handshake() native "SecureSocket_Handshake";
+
+ void init() native "SecureSocket_Init";
+
+ int processBuffer(int bufferIndex) native "SecureSocket_ProcessBuffer";
+
+ void registerHandshakeCompleteCallback(Function handshakeCompleteHandler)
+ native "SecureSocket_RegisterHandshakeCompleteCallback";
+
+ List<_ExternalBuffer> buffers;
+}
diff --git a/runtime/bin/socket_android.cc b/runtime/bin/socket_android.cc
index eac7d12..cffae9f 100644
--- a/runtime/bin/socket_android.cc
+++ b/runtime/bin/socket_android.cc
@@ -8,8 +8,9 @@
#include <string.h>
#include <unistd.h>
-#include "bin/fdutils.h"
#include "bin/socket.h"
+#include "bin/fdutils.h"
+#include "bin/log.h"
bool Socket::Initialize() {
@@ -25,7 +26,7 @@
fd = TEMP_FAILURE_RETRY(socket(AF_INET, SOCK_STREAM, 0));
if (fd < 0) {
- fprintf(stderr, "Error CreateConnect: %s\n", strerror(errno));
+ Log::PrintErr("Error CreateConnect: %s\n", strerror(errno));
return -1;
}
@@ -35,7 +36,7 @@
server = gethostbyname(host);
if (server == NULL) {
TEMP_FAILURE_RETRY(close(fd));
- fprintf(stderr, "Error CreateConnect: %s\n", strerror(errno));
+ Log::PrintErr("Error CreateConnect: %s\n", strerror(errno));
return -1;
}
@@ -93,7 +94,7 @@
getsockname(fd,
reinterpret_cast<struct sockaddr *>(&socket_address),
&size))) {
- fprintf(stderr, "Error getsockname: %s\n", strerror(errno));
+ Log::PrintErr("Error getsockname: %s\n", strerror(errno));
return 0;
}
return ntohs(socket_address.sin_port);
@@ -108,14 +109,14 @@
getpeername(fd,
reinterpret_cast<struct sockaddr *>(&socket_address),
&size))) {
- fprintf(stderr, "Error getpeername: %s\n", strerror(errno));
+ Log::PrintErr("Error getpeername: %s\n", strerror(errno));
return false;
}
if (inet_ntop(socket_address.sin_family,
reinterpret_cast<const void *>(&socket_address.sin_addr),
host,
INET_ADDRSTRLEN) == NULL) {
- fprintf(stderr, "Error inet_ntop: %s\n", strerror(errno));
+ Log::PrintErr("Error inet_ntop: %s\n", strerror(errno));
return false;
}
*port = ntohs(socket_address.sin_port);
@@ -185,7 +186,7 @@
fd = TEMP_FAILURE_RETRY(socket(AF_INET, SOCK_STREAM, 0));
if (fd < 0) {
- fprintf(stderr, "Error CreateBind: %s\n", strerror(errno));
+ Log::PrintErr("Error CreateBind: %s\n", strerror(errno));
return -1;
}
@@ -205,12 +206,12 @@
reinterpret_cast<struct sockaddr *>(&server_address),
sizeof(server_address))) < 0) {
TEMP_FAILURE_RETRY(close(fd));
- fprintf(stderr, "Error Bind: %s\n", strerror(errno));
+ Log::PrintErr("Error Bind: %s\n", strerror(errno));
return -1;
}
if (TEMP_FAILURE_RETRY(listen(fd, backlog)) != 0) {
- fprintf(stderr, "Error Listen: %s\n", strerror(errno));
+ Log::PrintErr("Error Listen: %s\n", strerror(errno));
return -1;
}
diff --git a/runtime/bin/socket_linux.cc b/runtime/bin/socket_linux.cc
index 89dd267..d8be1dc 100644
--- a/runtime/bin/socket_linux.cc
+++ b/runtime/bin/socket_linux.cc
@@ -9,6 +9,7 @@
#include <unistd.h>
#include "bin/fdutils.h"
+#include "bin/log.h"
#include "bin/socket.h"
@@ -25,7 +26,7 @@
fd = TEMP_FAILURE_RETRY(socket(AF_INET, SOCK_STREAM, 0));
if (fd < 0) {
- fprintf(stderr, "Error CreateConnect: %s\n", strerror(errno));
+ Log::PrintErr("Error CreateConnect: %s\n", strerror(errno));
return -1;
}
@@ -39,7 +40,7 @@
if (gethostbyname_r(
host, &server, temp_buf, kTempBufSize, &unused, &err) != 0) {
TEMP_FAILURE_RETRY(close(fd));
- fprintf(stderr, "Error CreateConnect: %s\n", strerror(errno));
+ Log::PrintErr("Error CreateConnect: %s\n", strerror(errno));
return -1;
}
@@ -97,7 +98,7 @@
getsockname(fd,
reinterpret_cast<struct sockaddr *>(&socket_address),
&size))) {
- fprintf(stderr, "Error getsockname: %s\n", strerror(errno));
+ Log::PrintErr("Error getsockname: %s\n", strerror(errno));
return 0;
}
return ntohs(socket_address.sin_port);
@@ -112,14 +113,14 @@
getpeername(fd,
reinterpret_cast<struct sockaddr *>(&socket_address),
&size))) {
- fprintf(stderr, "Error getpeername: %s\n", strerror(errno));
+ Log::PrintErr("Error getpeername: %s\n", strerror(errno));
return false;
}
if (inet_ntop(socket_address.sin_family,
reinterpret_cast<const void *>(&socket_address.sin_addr),
host,
INET_ADDRSTRLEN) == NULL) {
- fprintf(stderr, "Error inet_ntop: %s\n", strerror(errno));
+ Log::PrintErr("Error inet_ntop: %s\n", strerror(errno));
return false;
}
*port = ntohs(socket_address.sin_port);
@@ -188,7 +189,7 @@
fd = TEMP_FAILURE_RETRY(socket(AF_INET, SOCK_STREAM, 0));
if (fd < 0) {
- fprintf(stderr, "Error CreateBind: %s\n", strerror(errno));
+ Log::PrintErr("Error CreateBind: %s\n", strerror(errno));
return -1;
}
@@ -208,12 +209,12 @@
reinterpret_cast<struct sockaddr *>(&server_address),
sizeof(server_address))) < 0) {
TEMP_FAILURE_RETRY(close(fd));
- fprintf(stderr, "Error Bind: %s\n", strerror(errno));
+ Log::PrintErr("Error Bind: %s\n", strerror(errno));
return -1;
}
if (TEMP_FAILURE_RETRY(listen(fd, backlog)) != 0) {
- fprintf(stderr, "Error Listen: %s\n", strerror(errno));
+ Log::PrintErr("Error Listen: %s\n", strerror(errno));
return -1;
}
diff --git a/runtime/bin/socket_macos.cc b/runtime/bin/socket_macos.cc
index 32db433..275169f 100644
--- a/runtime/bin/socket_macos.cc
+++ b/runtime/bin/socket_macos.cc
@@ -9,6 +9,7 @@
#include <unistd.h>
#include "bin/fdutils.h"
+#include "bin/log.h"
#include "bin/socket.h"
@@ -25,7 +26,7 @@
fd = TEMP_FAILURE_RETRY(socket(AF_INET, SOCK_STREAM, 0));
if (fd < 0) {
- fprintf(stderr, "Error CreateConnect: %s\n", strerror(errno));
+ Log::PrintErr("Error CreateConnect: %s\n", strerror(errno));
return -1;
}
@@ -35,7 +36,7 @@
server = gethostbyname(host);
if (server == NULL) {
TEMP_FAILURE_RETRY(close(fd));
- fprintf(stderr, "Error CreateConnect: %s\n", strerror(errno));
+ Log::PrintErr("Error CreateConnect: %s\n", strerror(errno));
return -1;
}
@@ -93,7 +94,7 @@
getsockname(fd,
reinterpret_cast<struct sockaddr *>(&socket_address),
&size))) {
- fprintf(stderr, "Error getsockname: %s\n", strerror(errno));
+ Log::PrintErr("Error getsockname: %s\n", strerror(errno));
return 0;
}
return ntohs(socket_address.sin_port);
@@ -108,14 +109,14 @@
getpeername(fd,
reinterpret_cast<struct sockaddr *>(&socket_address),
&size))) {
- fprintf(stderr, "Error getpeername: %s\n", strerror(errno));
+ Log::PrintErr("Error getpeername: %s\n", strerror(errno));
return false;
}
if (inet_ntop(socket_address.sin_family,
reinterpret_cast<const void *>(&socket_address.sin_addr),
host,
INET_ADDRSTRLEN) == NULL) {
- fprintf(stderr, "Error inet_ntop: %s\n", strerror(errno));
+ Log::PrintErr("Error inet_ntop: %s\n", strerror(errno));
return false;
}
*port = ntohs(socket_address.sin_port);
@@ -184,7 +185,7 @@
fd = TEMP_FAILURE_RETRY(socket(AF_INET, SOCK_STREAM, 0));
if (fd < 0) {
- fprintf(stderr, "Error CreateBind: %s\n", strerror(errno));
+ Log::PrintErr("Error CreateBind: %s\n", strerror(errno));
return -1;
}
@@ -204,12 +205,12 @@
reinterpret_cast<struct sockaddr *>(&server_address),
sizeof(server_address))) < 0) {
TEMP_FAILURE_RETRY(close(fd));
- fprintf(stderr, "Error Bind: %s\n", strerror(errno));
+ Log::PrintErr("Error Bind: %s\n", strerror(errno));
return -1;
}
if (TEMP_FAILURE_RETRY(listen(fd, backlog)) != 0) {
- fprintf(stderr, "Error Listen: %s\n", strerror(errno));
+ Log::PrintErr("Error Listen: %s\n", strerror(errno));
return -1;
}
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index 7ce75d3..6e58985 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -239,8 +239,8 @@
bool _propagateError(Exception e) => false;
- abstract bool _isListenSocket();
- abstract bool _isPipe();
+ bool _isListenSocket();
+ bool _isPipe();
// Is this socket closed.
bool _closed;
@@ -465,7 +465,7 @@
}
void set onConnect(void callback()) {
- if (_seenFirstOutEvent || _outputStream != null) {
+ if (_seenFirstOutEvent) {
throw new StreamException(
"Cannot set connect handler when already connected");
}
@@ -509,7 +509,7 @@
if (_outputStream == null) {
if (_handlerMap[_SocketBase._OUT_EVENT] != null) {
throw new StreamException(
- "Cannot get input stream when socket handlers are used");
+ "Cannot get output stream when socket handlers are used");
}
_outputStream = new _SocketOutputStream(this);
}
diff --git a/runtime/bin/socket_win.cc b/runtime/bin/socket_win.cc
index 102f078..6e1a0bc 100644
--- a/runtime/bin/socket_win.cc
+++ b/runtime/bin/socket_win.cc
@@ -4,6 +4,7 @@
#include "bin/builtin.h"
#include "bin/eventhandler.h"
+#include "bin/log.h"
#include "bin/socket.h"
bool Socket::Initialize() {
@@ -12,7 +13,7 @@
WORD version_requested = MAKEWORD(1, 0);
err = WSAStartup(version_requested, &winsock_data);
if (err != 0) {
- fprintf(stderr, "Unable to initialize Winsock: %d\n", WSAGetLastError());
+ Log::PrintErr("Unable to initialize Winsock: %d\n", WSAGetLastError());
}
return err == 0;
}
@@ -43,7 +44,7 @@
if (getsockname(socket_handle->socket(),
reinterpret_cast<struct sockaddr *>(&socket_address),
&size)) {
- fprintf(stderr, "Error getsockname: %s\n", strerror(errno));
+ Log::PrintErr("Error getsockname: %s\n", strerror(errno));
return 0;
}
return ntohs(socket_address.sin_port);
@@ -58,7 +59,7 @@
if (getpeername(socket_handle->socket(),
reinterpret_cast<struct sockaddr *>(&socket_address),
&size)) {
- fprintf(stderr, "Error getpeername: %s\n", strerror(errno));
+ Log::PrintErr("Error getpeername: %s\n", strerror(errno));
return false;
}
*port = ntohs(socket_address.sin_port);
@@ -72,7 +73,7 @@
host,
&len);
if (err != 0) {
- fprintf(stderr, "Error WSAAddressToString: %d\n", WSAGetLastError());
+ Log::PrintErr("Error WSAAddressToString: %d\n", WSAGetLastError());
return false;
}
return true;
diff --git a/runtime/bin/tls_socket.cc b/runtime/bin/tls_socket.cc
deleted file mode 100644
index c4bc0a5..0000000
--- a/runtime/bin/tls_socket.cc
+++ /dev/null
@@ -1,385 +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.
-
-#include "bin/tls_socket.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <nss.h>
-#include <prerror.h>
-#include <prinit.h>
-#include <prnetdb.h>
-#include <ssl.h>
-
-#include "bin/builtin.h"
-#include "bin/dartutils.h"
-#include "bin/net/nss_memio.h"
-#include "bin/thread.h"
-#include "bin/utils.h"
-#include "platform/utils.h"
-
-#include "include/dart_api.h"
-
-bool TlsFilter::library_initialized_ = false;
-dart::Mutex TlsFilter::mutex_; // To protect library initialization.
-static const int kTlsFilterNativeFieldIndex = 0;
-
-static TlsFilter* GetTlsFilter(Dart_NativeArguments args) {
- TlsFilter* filter;
- Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
- ASSERT(Dart_IsInstance(dart_this));
- ThrowIfError(Dart_GetNativeInstanceField(
- dart_this,
- kTlsFilterNativeFieldIndex,
- reinterpret_cast<intptr_t*>(&filter)));
- return filter;
-}
-
-
-static void SetTlsFilter(Dart_NativeArguments args, TlsFilter* filter) {
- Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
- ASSERT(Dart_IsInstance(dart_this));
- ThrowIfError(Dart_SetNativeInstanceField(
- dart_this,
- kTlsFilterNativeFieldIndex,
- reinterpret_cast<intptr_t>(filter)));
-}
-
-
-void FUNCTION_NAME(TlsSocket_Init)(Dart_NativeArguments args) {
- Dart_EnterScope();
- Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
- TlsFilter* filter = new TlsFilter;
- SetTlsFilter(args, filter);
- filter->Init(dart_this);
- Dart_ExitScope();
-}
-
-
-void FUNCTION_NAME(TlsSocket_Connect)(Dart_NativeArguments args) {
- Dart_EnterScope();
- Dart_Handle host_name = ThrowIfError(Dart_GetNativeArgument(args, 1));
- Dart_Handle port_object = ThrowIfError(Dart_GetNativeArgument(args, 2));
-
- const char* host_name_string = NULL;
- // TODO(whesse): Is truncating a Dart string containing \0 what we want?
- ThrowIfError(Dart_StringToCString(host_name, &host_name_string));
-
- int64_t port;
- if (!DartUtils::GetInt64Value(port_object, &port) ||
- port < 0 || port > 65535) {
- Dart_ThrowException(DartUtils::NewDartArgumentError(
- "Illegal port parameter in TlsSocket"));
- }
-
- GetTlsFilter(args)->Connect(host_name_string, static_cast<int>(port));
- Dart_ExitScope();
-}
-
-
-void FUNCTION_NAME(TlsSocket_Destroy)(Dart_NativeArguments args) {
- Dart_EnterScope();
- TlsFilter* filter = GetTlsFilter(args);
- SetTlsFilter(args, NULL);
- filter->Destroy();
- delete filter;
- Dart_ExitScope();
-}
-
-
-void FUNCTION_NAME(TlsSocket_Handshake)(Dart_NativeArguments args) {
- Dart_EnterScope();
- GetTlsFilter(args)->Handshake();
- Dart_ExitScope();
-}
-
-
-void FUNCTION_NAME(TlsSocket_RegisterHandshakeCompleteCallback)(
- Dart_NativeArguments args) {
- Dart_EnterScope();
- Dart_Handle handshake_complete =
- ThrowIfError(Dart_GetNativeArgument(args, 1));
- if (!Dart_IsClosure(handshake_complete)) {
- Dart_ThrowException(DartUtils::NewDartArgumentError(
- "Illegal argument to RegisterHandshakeCompleteCallback"));
- }
- GetTlsFilter(args)->RegisterHandshakeCompleteCallback(handshake_complete);
- Dart_ExitScope();
-}
-
-
-void FUNCTION_NAME(TlsSocket_ProcessBuffer)(Dart_NativeArguments args) {
- Dart_EnterScope();
- Dart_Handle buffer_id_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
- int64_t buffer_id = DartUtils::GetIntegerValue(buffer_id_object);
- if (buffer_id < 0 || buffer_id >= TlsFilter::kNumBuffers) {
- Dart_ThrowException(DartUtils::NewDartArgumentError(
- "Illegal argument to ProcessBuffer"));
- }
-
- intptr_t bytes_read =
- GetTlsFilter(args)->ProcessBuffer(static_cast<int>(buffer_id));
- Dart_SetReturnValue(args, Dart_NewInteger(bytes_read));
- Dart_ExitScope();
-}
-
-
-void FUNCTION_NAME(TlsSocket_SetCertificateDatabase)
- (Dart_NativeArguments args) {
- Dart_EnterScope();
- Dart_Handle dart_pkcert_dir = ThrowIfError(Dart_GetNativeArgument(args, 0));
- // Check that the type is string, and get the UTF-8 C string value from it.
- if (Dart_IsString(dart_pkcert_dir)) {
- const char* pkcert_dir = NULL;
- ThrowIfError(Dart_StringToCString(dart_pkcert_dir, &pkcert_dir));
- TlsFilter::InitializeLibrary(pkcert_dir);
- } else {
- Dart_ThrowException(DartUtils::NewDartArgumentError(
- "Non-String argument to SetCertificateDatabase"));
- }
- Dart_ExitScope();
-}
-
-
-void TlsFilter::Init(Dart_Handle dart_this) {
- string_start_ = ThrowIfError(
- Dart_NewPersistentHandle(DartUtils::NewString("start")));
- string_length_ = ThrowIfError(
- Dart_NewPersistentHandle(DartUtils::NewString("length")));
-
- InitializeBuffers(dart_this);
- memio_ = memio_CreateIOLayer(kMemioBufferSize);
-}
-
-
-void TlsFilter::InitializeBuffers(Dart_Handle dart_this) {
- // Create TlsFilter buffers as ExternalUint8Array objects.
- Dart_Handle dart_buffers_object = ThrowIfError(
- Dart_GetField(dart_this, DartUtils::NewString("buffers")));
- Dart_Handle dart_buffer_object =
- Dart_ListGetAt(dart_buffers_object, kReadPlaintext);
- Dart_Handle tls_external_buffer_class =
- Dart_InstanceGetClass(dart_buffer_object);
- Dart_Handle dart_buffer_size = ThrowIfError(
- Dart_GetField(tls_external_buffer_class, DartUtils::NewString("SIZE")));
- buffer_size_ = DartUtils::GetIntegerValue(dart_buffer_size);
- if (buffer_size_ <= 0 || buffer_size_ > 1024 * 1024) {
- Dart_ThrowException(
- DartUtils::NewString("Invalid buffer size in _TlsExternalBuffer"));
- }
-
- Dart_Handle data_identifier = DartUtils::NewString("data");
- for (int i = 0; i < kNumBuffers; ++i) {
- dart_buffer_objects_[i] = ThrowIfError(
- Dart_NewPersistentHandle(Dart_ListGetAt(dart_buffers_object, i)));
- buffers_[i] = new uint8_t[buffer_size_];
- Dart_Handle data = ThrowIfError(
- Dart_NewExternalByteArray(buffers_[i], buffer_size_, NULL, NULL));
- ThrowIfError(Dart_SetField(dart_buffer_objects_[i],
- data_identifier,
- data));
- }
-}
-
-
-void TlsFilter::RegisterHandshakeCompleteCallback(Dart_Handle complete) {
- ASSERT(NULL == handshake_complete_);
- handshake_complete_ = ThrowIfError(Dart_NewPersistentHandle(complete));
-}
-
-
-void TlsFilter::InitializeLibrary(const char* pkcert_database) {
- MutexLocker locker(&mutex_);
- if (!library_initialized_) {
- PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
- // TODO(whesse): Verify there are no UTF-8 issues here.
- SECStatus status = NSS_Init(pkcert_database);
- if (status != SECSuccess) {
- ThrowPRException("Unsuccessful NSS_Init call.");
- }
-
- status = NSS_SetDomesticPolicy();
- if (status != SECSuccess) {
- ThrowPRException("Unsuccessful NSS_SetDomesticPolicy call.");
- }
- } else {
- ThrowException("Called TlsFilter::InitializeLibrary more than once");
- }
-}
-
-
-void TlsFilter::Connect(const char* host, int port) {
- if (in_handshake_) {
- ThrowException("Connect called while already in handshake state.");
- }
- PRFileDesc* my_socket = memio_;
-
- my_socket = SSL_ImportFD(NULL, my_socket);
- if (my_socket == NULL) {
- ThrowPRException("Unsuccessful SSL_ImportFD call");
- }
-
- if (SSL_SetURL(my_socket, host) == -1) {
- ThrowPRException("Unsuccessful SetURL call");
- }
-
- SECStatus status = SSL_ResetHandshake(my_socket, PR_FALSE);
- if (status != SECSuccess) {
- ThrowPRException("Unsuccessful SSL_ResetHandshake call");
- }
-
- // SetPeerAddress
- PRNetAddr host_address;
- char host_entry_buffer[PR_NETDB_BUF_SIZE];
- PRHostEnt host_entry;
- PRStatus rv = PR_GetHostByName(host, host_entry_buffer,
- PR_NETDB_BUF_SIZE, &host_entry);
- if (rv != PR_SUCCESS) {
- ThrowPRException("Unsuccessful PR_GetHostByName call");
- }
-
- int index = PR_EnumerateHostEnt(0, &host_entry, port, &host_address);
- if (index == -1 || index == 0) {
- ThrowPRException("Unsuccessful PR_EnumerateHostEnt call");
- }
-
- memio_SetPeerName(my_socket, &host_address);
- memio_ = my_socket;
-}
-
-
-void TlsFilter::Handshake() {
- SECStatus status = SSL_ForceHandshake(memio_);
- if (status == SECSuccess) {
- if (in_handshake_) {
- ThrowIfError(Dart_InvokeClosure(handshake_complete_, 0, NULL));
- in_handshake_ = false;
- }
- } else {
- PRErrorCode error = PR_GetError();
- if (error == PR_WOULD_BLOCK_ERROR) {
- if (!in_handshake_) {
- in_handshake_ = true;
- }
- } else {
- ThrowPRException("Unexpected handshake error");
- }
- }
-}
-
-
-void TlsFilter::Destroy() {
- for (int i = 0; i < kNumBuffers; ++i) {
- Dart_DeletePersistentHandle(dart_buffer_objects_[i]);
- delete[] buffers_[i];
- }
- Dart_DeletePersistentHandle(string_start_);
- Dart_DeletePersistentHandle(string_length_);
- Dart_DeletePersistentHandle(handshake_complete_);
- // TODO(whesse): Free NSS objects here.
-}
-
-
-intptr_t TlsFilter::ProcessBuffer(int buffer_index) {
- Dart_Handle buffer_object = dart_buffer_objects_[buffer_index];
- Dart_Handle start_object = ThrowIfError(
- Dart_GetField(buffer_object, string_start_));
- Dart_Handle length_object = ThrowIfError(
- Dart_GetField(buffer_object, string_length_));
- int64_t unsafe_start = DartUtils::GetIntegerValue(start_object);
- int64_t unsafe_length = DartUtils::GetIntegerValue(length_object);
- ASSERT(unsafe_start >= 0);
- ASSERT(unsafe_start < buffer_size_);
- ASSERT(unsafe_length >= 0);
- ASSERT(unsafe_length <= buffer_size_);
- intptr_t start = static_cast<intptr_t>(unsafe_start);
- intptr_t length = static_cast<intptr_t>(unsafe_length);
- uint8_t* buffer = buffers_[buffer_index];
-
- int bytes_processed = 0;
- switch (buffer_index) {
- case kReadPlaintext: {
- int bytes_free = buffer_size_ - start - length;
- bytes_processed = PR_Read(memio_,
- buffer + start + length,
- bytes_free);
- if (bytes_processed < 0) {
- ASSERT(bytes_processed == -1);
- // TODO(whesse): Handle unexpected errors here.
- PRErrorCode pr_error = PR_GetError();
- if (PR_WOULD_BLOCK_ERROR != pr_error) {
- ThrowPRException("Error reading plaintext from TlsFilter");
- }
- bytes_processed = 0;
- }
- break;
- }
-
- case kWriteEncrypted: {
- const uint8_t* buf1;
- const uint8_t* buf2;
- unsigned int len1;
- unsigned int len2;
- int bytes_free = buffer_size_ - start - length;
- memio_Private* secret = memio_GetSecret(memio_);
- memio_GetWriteParams(secret, &buf1, &len1, &buf2, &len2);
- int bytes_to_send =
- dart::Utils::Minimum(len1, static_cast<unsigned>(bytes_free));
- if (bytes_to_send > 0) {
- memmove(buffer + start + length, buf1, bytes_to_send);
- bytes_processed = bytes_to_send;
- }
- bytes_to_send = dart::Utils::Minimum(len2,
- static_cast<unsigned>(bytes_free - bytes_processed));
- if (bytes_to_send > 0) {
- memmove(buffer + start + length + bytes_processed, buf2,
- bytes_to_send);
- bytes_processed += bytes_to_send;
- }
- if (bytes_processed > 0) {
- memio_PutWriteResult(secret, bytes_processed);
- }
- break;
- }
-
- case kReadEncrypted: {
- if (length > 0) {
- bytes_processed = length;
- memio_Private* secret = memio_GetSecret(memio_);
- uint8_t* memio_buf;
- int free_bytes = memio_GetReadParams(secret, &memio_buf);
- if (free_bytes < bytes_processed) bytes_processed = free_bytes;
- memmove(memio_buf,
- buffer + start,
- bytes_processed);
- memio_PutReadResult(secret, bytes_processed);
- }
- break;
- }
-
- case kWritePlaintext: {
- if (length > 0) {
- bytes_processed = PR_Write(memio_,
- buffer + start,
- length);
- }
-
- if (bytes_processed < 0) {
- ASSERT(bytes_processed == -1);
- // TODO(whesse): Handle unexpected errors here.
- PRErrorCode pr_error = PR_GetError();
- if (PR_WOULD_BLOCK_ERROR != pr_error) {
- ThrowPRException("Error reading plaintext from TlsFilter");
- }
- bytes_processed = 0;
- }
- break;
- }
- }
- return bytes_processed;
-}
diff --git a/runtime/bin/tls_socket_patch.dart b/runtime/bin/tls_socket_patch.dart
deleted file mode 100644
index 73e40e8..0000000
--- a/runtime/bin/tls_socket_patch.dart
+++ /dev/null
@@ -1,52 +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.
-
-patch class TlsSocket {
- /* patch */ static void setCertificateDatabase(String pkcertDirectory)
- native "TlsSocket_SetCertificateDatabase";
-}
-
-
-patch class _TlsFilter {
- /* patch */ factory _TlsFilter() => new _TlsFilterImpl();
-}
-
-
-/**
- * _TlsFilterImpl wraps a filter that encrypts and decrypts data travelling
- * over a TLS encrypted socket. The filter also handles the handshaking
- * and certificate verification.
- *
- * The filter exposes its input and output buffers as Dart objects that
- * are backed by an external C array of bytes, so that both Dart code and
- * native code can access the same data.
- */
-class _TlsFilterImpl extends NativeFieldWrapperClass1 implements _TlsFilter {
- _TlsFilterImpl() {
- buffers = new List<_TlsExternalBuffer>(_TlsSocket.NUM_BUFFERS);
- for (int i = 0; i < _TlsSocket.NUM_BUFFERS; ++i) {
- buffers[i] = new _TlsExternalBuffer();
- }
- }
-
- void connect(String hostName, int port) native "TlsSocket_Connect";
-
- void destroy() {
- buffers = null;
- _destroy();
- }
-
- void _destroy() native "TlsSocket_Destroy";
-
- void handshake() native "TlsSocket_Handshake";
-
- void init() native "TlsSocket_Init";
-
- int processBuffer(int bufferIndex) native "TlsSocket_ProcessBuffer";
-
- void registerHandshakeCompleteCallback(Function handshakeCompleteHandler)
- native "TlsSocket_RegisterHandshakeCompleteCallback";
-
- List<_TlsExternalBuffer> buffers;
-}
diff --git a/runtime/bin/utils_win.cc b/runtime/bin/utils_win.cc
index 9ee1777..f9603f8 100644
--- a/runtime/bin/utils_win.cc
+++ b/runtime/bin/utils_win.cc
@@ -5,6 +5,7 @@
#include <errno.h>
#include "bin/utils.h"
+#include "bin/log.h"
static void FormatMessageIntoBuffer(DWORD code,
char* buffer,
@@ -19,7 +20,7 @@
NULL);
if (message_size == 0) {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
- fprintf(stderr, "FormatMessage failed %d\n", GetLastError());
+ Log::PrintErr("FormatMessage failed %d\n", GetLastError());
}
snprintf(buffer, buffer_length, "OS Error %d", code);
}
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 8cc518a..821014c 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -1388,7 +1388,7 @@
* \return The String object if no error occurs. Otherwise returns
* an error handle.
*/
-DART_EXPORT Dart_Handle Dart_NewStringFromUTF32(const uint32_t* utf32_array,
+DART_EXPORT Dart_Handle Dart_NewStringFromUTF32(const int32_t* utf32_array,
intptr_t length);
/**
diff --git a/runtime/lib/array.dart b/runtime/lib/array.dart
index 1fb17fb..5bef0d0 100644
--- a/runtime/lib/array.dart
+++ b/runtime/lib/array.dart
@@ -138,6 +138,10 @@
"Cannot remove in a non-extendable array");
}
+ E get first {
+ return this[0];
+ }
+
E get last {
return this[length - 1];
}
@@ -285,6 +289,10 @@
"Cannot remove in a non-extendable array");
}
+ E get first {
+ return this[0];
+ }
+
E get last {
return this[length - 1];
}
diff --git a/runtime/lib/array_patch.dart b/runtime/lib/array_patch.dart
index 5bb7ec2c..2887a99 100644
--- a/runtime/lib/array_patch.dart
+++ b/runtime/lib/array_patch.dart
@@ -5,7 +5,7 @@
// Note that the optimizing compiler depends on the algorithm which
// returns a _GrowableObjectArray if length is null, otherwise returns
// fixed size array.
-patch class _ListImpl<E> {
+patch class List<E> {
/* patch */ factory List([int length = null]) {
if (length == null) {
return new _GrowableObjectArray<E>();
@@ -14,14 +14,6 @@
}
}
- /* patch */ factory List.from(Iterable<E> other) {
- _GrowableObjectArray<E> list = new _GrowableObjectArray<E>();
- for (final e in other) {
- list.add(e);
- }
- return list;
- }
-
// Factory constructing a mutable List from a parser generated List literal.
// [elements] contains elements that are already type checked.
factory List._fromLiteral(List elements) {
diff --git a/runtime/lib/byte_array.dart b/runtime/lib/byte_array.dart
index 0f97c3d..aa8e5dc 100644
--- a/runtime/lib/byte_array.dart
+++ b/runtime/lib/byte_array.dart
@@ -115,11 +115,11 @@
abstract class _ByteArrayBase {
- abstract int lengthInBytes();
+ int lengthInBytes();
- abstract int bytesPerElement();
+ int bytesPerElement();
- abstract operator[](int index);
+ operator[](int index);
// Methods implementing the Collection interface.
@@ -184,7 +184,7 @@
}
void sort([Comparator compare = Comparable.compare]) {
- _Sort.sort(this, compare);
+ coreSort(this, compare);
}
int indexOf(element, [int start = 0]) {
@@ -206,6 +206,10 @@
"Cannot remove from a non-extendable array");
}
+ get first {
+ return this[0];
+ }
+
get last {
return this[length - 1];
}
@@ -1601,7 +1605,7 @@
class _ByteArrayViewBase {
- abstract num operator[](int index);
+ num operator[](int index);
// Methods implementing the Collection interface.
@@ -1637,7 +1641,7 @@
return this.length == 0;
}
- abstract int get length;
+ int get length;
// Methods implementing the List interface.
@@ -1662,7 +1666,7 @@
}
void sort([Comparator compare = Comparable.compare]) {
- _Sort.sort(this, compare);
+ coreSort(this, compare);
}
int indexOf(element, [int start = 0]) {
@@ -1684,6 +1688,10 @@
"Cannot remove from a non-extendable array");
}
+ get first {
+ return this[0];
+ }
+
get last {
return this[length - 1];
}
diff --git a/runtime/lib/double.cc b/runtime/lib/double.cc
index 05977ba..76babac 100644
--- a/runtime/lib/double.cc
+++ b/runtime/lib/double.cc
@@ -11,6 +11,7 @@
#include "vm/exceptions.h"
#include "vm/native_entry.h"
#include "vm/object.h"
+#include "vm/symbols.h"
namespace dart {
@@ -202,6 +203,61 @@
}
+DEFINE_NATIVE_ENTRY(Double_parse, 1) {
+ GET_NATIVE_ARGUMENT(String, value, arguments->NativeArgAt(0));
+ const String& dummy_key = String::Handle(Symbols::Empty());
+ Scanner scanner(value, dummy_key);
+ const Scanner::GrowableTokenStream& tokens = scanner.GetStream();
+ String* number_string;
+ bool is_positive;
+ if (Scanner::IsValidLiteral(tokens,
+ Token::kDOUBLE,
+ &is_positive,
+ &number_string)) {
+ const char* cstr = number_string->ToCString();
+ char* p_end = NULL;
+ double double_value = strtod(cstr, &p_end);
+ ASSERT(p_end != cstr);
+ if (!is_positive) {
+ double_value = -double_value;
+ }
+ return Double::New(double_value);
+ }
+
+ if (Scanner::IsValidLiteral(tokens,
+ Token::kINTEGER,
+ &is_positive,
+ &number_string)) {
+ Integer& res = Integer::Handle(Integer::New(*number_string));
+ if (is_positive) {
+ return Double::New(res.AsDoubleValue());
+ }
+ return Double::New(-res.AsDoubleValue());
+ }
+
+ // Infinity and nan.
+ if (Scanner::IsValidLiteral(tokens,
+ Token::kIDENT,
+ &is_positive,
+ &number_string)) {
+ if (number_string->Equals("NaN")) {
+ return Double::New(NAN);
+ }
+ if (number_string->Equals("Infinity")) {
+ if (is_positive) {
+ return Double::New(INFINITY);
+ }
+ return Double::New(-INFINITY);
+ }
+ }
+
+ GrowableArray<const Object*> args;
+ args.Add(&value);
+ Exceptions::ThrowByType(Exceptions::kFormat, args);
+ return Object::null();
+}
+
+
DEFINE_NATIVE_ENTRY(Double_toStringAsFixed, 2) {
// The boundaries are exclusive.
static const double kLowerBoundary = -1e21;
diff --git a/runtime/lib/double.dart b/runtime/lib/double.dart
index f4025f3..aee84e2 100644
--- a/runtime/lib/double.dart
+++ b/runtime/lib/double.dart
@@ -114,7 +114,9 @@
if (exponent == 0) {
return 1.0; // ECMA-262 15.8.2.13
}
- // Throw NullPointerException if exponent is null.
+ if (exponent is! num) {
+ throw new ArgumentError(null);
+ }
double doubleExponent = exponent.toDouble();
if (isNaN || exponent.isNaN) {
return double.NAN;
diff --git a/runtime/lib/double_patch.dart b/runtime/lib/double_patch.dart
index d293249..5e6cc11 100644
--- a/runtime/lib/double_patch.dart
+++ b/runtime/lib/double_patch.dart
@@ -7,5 +7,5 @@
patch class double {
/* patch */
- static double parse(String string) native "MathNatives_parseDouble";
+ static double parse(String string) native "Double_parse";
}
diff --git a/runtime/lib/errors_patch.dart b/runtime/lib/errors_patch.dart
index d09dc3d..12caead 100644
--- a/runtime/lib/errors_patch.dart
+++ b/runtime/lib/errors_patch.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.
-patch class NoSuchMethodError {
+patch class Error {
/* patch */ static String _objectToString(Object object) {
return Object._toString(object);
}
diff --git a/runtime/lib/expando_patch.dart b/runtime/lib/expando_patch.dart
index a218af6..5c61969 100644
--- a/runtime/lib/expando_patch.dart
+++ b/runtime/lib/expando_patch.dart
@@ -54,10 +54,7 @@
}
static _checkType(object) {
- if (object == null) {
- throw new NullPointerException();
- }
- if (object is bool || object is num || object is String) {
+ if (object == null || object is bool || object is num || object is String) {
throw new ArgumentError(object);
}
}
diff --git a/runtime/lib/growable_array.dart b/runtime/lib/growable_array.dart
index a34bca0..2e012c2 100644
--- a/runtime/lib/growable_array.dart
+++ b/runtime/lib/growable_array.dart
@@ -145,6 +145,10 @@
return elem;
}
+ T get first {
+ return this[0];
+ }
+
T get last {
return this[length - 1];
}
diff --git a/runtime/lib/integers.cc b/runtime/lib/integers.cc
index c9cf18d..9c379ca 100644
--- a/runtime/lib/integers.cc
+++ b/runtime/lib/integers.cc
@@ -9,6 +9,7 @@
#include "vm/exceptions.h"
#include "vm/native_entry.h"
#include "vm/object.h"
+#include "vm/symbols.h"
namespace dart {
@@ -172,6 +173,32 @@
}
+DEFINE_NATIVE_ENTRY(Integer_parse, 1) {
+ GET_NATIVE_ARGUMENT(String, value, arguments->NativeArgAt(0));
+ const String& dummy_key = String::Handle(Symbols::Empty());
+ Scanner scanner(value, dummy_key);
+ const Scanner::GrowableTokenStream& tokens = scanner.GetStream();
+ String* int_string;
+ bool is_positive;
+ if (Scanner::IsValidLiteral(tokens,
+ Token::kINTEGER,
+ &is_positive,
+ &int_string)) {
+ if (is_positive) {
+ return Integer::New(*int_string);
+ }
+ String& temp = String::Handle();
+ temp = String::Concat(String::Handle(Symbols::New("-")), *int_string);
+ return Integer::New(temp);
+ }
+
+ GrowableArray<const Object*> args;
+ args.Add(&value);
+ Exceptions::ThrowByType(Exceptions::kFormat, args);
+ return Object::null();
+}
+
+
static RawInteger* ShiftOperationHelper(Token::Kind kind,
const Integer& value,
const Smi& amount) {
diff --git a/runtime/lib/integers_patch.dart b/runtime/lib/integers_patch.dart
index c931ed4..162c050 100644
--- a/runtime/lib/integers_patch.dart
+++ b/runtime/lib/integers_patch.dart
@@ -6,5 +6,5 @@
// VM implementation of int.
patch class int {
- /* patch */ static int parse(String str) native "MathNatives_parseInt";
+ /* patch */ static int parse(String str) native "Integer_parse";
}
diff --git a/runtime/lib/lib_sources.gypi b/runtime/lib/lib_sources.gypi
index 2bffa7e..28c9afd 100644
--- a/runtime/lib/lib_sources.gypi
+++ b/runtime/lib/lib_sources.gypi
@@ -28,8 +28,6 @@
'integers_patch.dart',
'invocation_mirror_patch.dart',
'map_patch.dart',
- 'math.dart',
- 'math.cc',
'object.cc',
'object_patch.dart',
'print_patch.dart',
diff --git a/runtime/lib/math.cc b/runtime/lib/math.cc
index de48b16..ff4e6af 100644
--- a/runtime/lib/math.cc
+++ b/runtime/lib/math.cc
@@ -10,168 +10,60 @@
#include "vm/exceptions.h"
#include "vm/native_entry.h"
#include "vm/object.h"
-#include "vm/random.h"
#include "vm/scanner.h"
#include "vm/symbols.h"
namespace dart {
-DEFINE_NATIVE_ENTRY(MathNatives_sqrt, 1) {
+DEFINE_NATIVE_ENTRY(Math_sqrt, 1) {
GET_NATIVE_ARGUMENT(Double, operand, arguments->NativeArgAt(0));
return Double::New(sqrt(operand.value()));
}
-DEFINE_NATIVE_ENTRY(MathNatives_sin, 1) {
+DEFINE_NATIVE_ENTRY(Math_sin, 1) {
GET_NATIVE_ARGUMENT(Double, operand, arguments->NativeArgAt(0));
return Double::New(sin(operand.value()));
}
-DEFINE_NATIVE_ENTRY(MathNatives_cos, 1) {
+DEFINE_NATIVE_ENTRY(Math_cos, 1) {
GET_NATIVE_ARGUMENT(Double, operand, arguments->NativeArgAt(0));
return Double::New(cos(operand.value()));
}
-DEFINE_NATIVE_ENTRY(MathNatives_tan, 1) {
+DEFINE_NATIVE_ENTRY(Math_tan, 1) {
GET_NATIVE_ARGUMENT(Double, operand, arguments->NativeArgAt(0));
return Double::New(tan(operand.value()));
}
-DEFINE_NATIVE_ENTRY(MathNatives_asin, 1) {
+DEFINE_NATIVE_ENTRY(Math_asin, 1) {
GET_NATIVE_ARGUMENT(Double, operand, arguments->NativeArgAt(0));
return Double::New(asin(operand.value()));
}
-DEFINE_NATIVE_ENTRY(MathNatives_acos, 1) {
+DEFINE_NATIVE_ENTRY(Math_acos, 1) {
GET_NATIVE_ARGUMENT(Double, operand, arguments->NativeArgAt(0));
return Double::New(acos(operand.value()));
}
-DEFINE_NATIVE_ENTRY(MathNatives_atan, 1) {
+DEFINE_NATIVE_ENTRY(Math_atan, 1) {
GET_NATIVE_ARGUMENT(Double, operand, arguments->NativeArgAt(0));
return Double::New(atan(operand.value()));
}
-DEFINE_NATIVE_ENTRY(MathNatives_atan2, 2) {
+DEFINE_NATIVE_ENTRY(Math_atan2, 2) {
GET_NATIVE_ARGUMENT(Double, operand1, arguments->NativeArgAt(0));
GET_NATIVE_ARGUMENT(Double, operand2, arguments->NativeArgAt(1));
return Double::New(atan2(operand1.value(), operand2.value()));
}
-DEFINE_NATIVE_ENTRY(MathNatives_exp, 1) {
+DEFINE_NATIVE_ENTRY(Math_exp, 1) {
GET_NATIVE_ARGUMENT(Double, operand, arguments->NativeArgAt(0));
return Double::New(exp(operand.value()));
}
-DEFINE_NATIVE_ENTRY(MathNatives_log, 1) {
+DEFINE_NATIVE_ENTRY(Math_log, 1) {
GET_NATIVE_ARGUMENT(Double, operand, arguments->NativeArgAt(0));
return Double::New(log(operand.value()));
}
-DEFINE_NATIVE_ENTRY(MathNatives_random, 0) {
- return Double::New(static_cast<double>(Random::RandomInt32()-1)/0x80000000);
-}
-
-
-// TODO(srdjan): Investigate for performance hit; the integer and double parsing
-// may not be efficient as we need to generate two extra growable arrays.
-static bool IsValidLiteral(const Scanner::GrowableTokenStream& tokens,
- Token::Kind literal_kind,
- bool* is_positive,
- String** value) {
- if ((tokens.length() == 2) &&
- (tokens[0].kind == literal_kind) &&
- (tokens[1].kind == Token::kEOS)) {
- *is_positive = true;
- *value = tokens[0].literal;
- return true;
- }
- if ((tokens.length() == 3) &&
- ((tokens[0].kind == Token::kTIGHTADD) ||
- (tokens[0].kind == Token::kSUB)) &&
- (tokens[1].kind == literal_kind) &&
- (tokens[2].kind == Token::kEOS)) {
- // Check there is no space between "+/-" and number.
- if ((tokens[0].offset + 1) != tokens[1].offset) {
- return false;
- }
- *is_positive = tokens[0].kind == Token::kTIGHTADD;
- *value = tokens[1].literal;
- return true;
- }
- return false;
-}
-
-
-DEFINE_NATIVE_ENTRY(MathNatives_parseInt, 1) {
- GET_NATIVE_ARGUMENT(String, value, arguments->NativeArgAt(0));
- const String& dummy_key = String::Handle(Symbols::Empty());
- Scanner scanner(value, dummy_key);
- const Scanner::GrowableTokenStream& tokens = scanner.GetStream();
- String* int_string;
- bool is_positive;
- if (IsValidLiteral(tokens, Token::kINTEGER, &is_positive, &int_string)) {
- if (is_positive) {
- return Integer::New(*int_string);
- } else {
- String& temp = String::Handle();
- temp = String::Concat(String::Handle(Symbols::New("-")),
- *int_string);
- return Integer::New(temp);
- }
- } else {
- GrowableArray<const Object*> args;
- args.Add(&value);
- Exceptions::ThrowByType(Exceptions::kFormat, args);
- return Object::null();
- }
-}
-
-
-DEFINE_NATIVE_ENTRY(MathNatives_parseDouble, 1) {
- GET_NATIVE_ARGUMENT(String, value, arguments->NativeArgAt(0));
- const String& dummy_key = String::Handle(Symbols::Empty());
- Scanner scanner(value, dummy_key);
- const Scanner::GrowableTokenStream& tokens = scanner.GetStream();
- String* number_string;
- bool is_positive;
- if (IsValidLiteral(tokens, Token::kDOUBLE, &is_positive, &number_string)) {
- const char* cstr = number_string->ToCString();
- char* p_end = NULL;
- double double_value = strtod(cstr, &p_end);
- ASSERT(p_end != cstr);
- if (!is_positive) {
- double_value = -double_value;
- }
- return Double::New(double_value);
- }
-
- if (IsValidLiteral(tokens, Token::kINTEGER, &is_positive, &number_string)) {
- Integer& res = Integer::Handle(Integer::New(*number_string));
- if (is_positive) {
- return Double::New(res.AsDoubleValue());
- } else {
- return Double::New(-res.AsDoubleValue());
- }
- }
-
- // Infinity and nan.
- if (IsValidLiteral(tokens, Token::kIDENT, &is_positive, &number_string)) {
- if (number_string->Equals("NaN")) {
- return Double::New(NAN);
- }
- if (number_string->Equals("Infinity")) {
- if (is_positive) {
- return Double::New(INFINITY);
- } else {
- return Double::New(-INFINITY);
- }
- }
- }
-
- GrowableArray<const Object*> args;
- args.Add(&value);
- Exceptions::ThrowByType(Exceptions::kFormat, args);
- return Object::null();
-}
-
} // namespace dart
diff --git a/runtime/lib/math.dart b/runtime/lib/math.dart
deleted file mode 100644
index bb32560..0000000
--- a/runtime/lib/math.dart
+++ /dev/null
@@ -1,36 +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.
-
-class MathNatives {
- static num pow(num value, num exponent) {
- if (exponent is int) {
- return value.pow(exponent);
- }
- // Double.pow will call exponent.toDouble().
- return value.toDouble().pow(exponent);
- }
- static double random() => _random();
- static double sqrt(num value) => _sqrt(value.toDouble());
- static double sin(num value) => _sin(value.toDouble());
- static double cos(num value) => _cos(value.toDouble());
- static double tan(num value) => _tan(value.toDouble());
- static double acos(num value) => _acos(value.toDouble());
- static double asin(num value) => _asin(value.toDouble());
- static double atan(num value) => _atan(value.toDouble());
- static double atan2(num a, num b) => _atan2(a.toDouble(), b.toDouble());
- static double exp(num value) => _exp(value.toDouble());
- static double log(num value) => _log(value.toDouble());
-
- static double _random() native "MathNatives_random";
- static double _sqrt(double value) native "MathNatives_sqrt";
- static double _sin(double value) native "MathNatives_sin";
- static double _cos(double value) native "MathNatives_cos";
- static double _tan(double value) native "MathNatives_tan";
- static double _acos(double value) native "MathNatives_acos";
- static double _asin(double value) native "MathNatives_asin";
- static double _atan(double value) native "MathNatives_atan";
- static double _atan2(double a, double b) native "MathNatives_atan2";
- static double _exp(double value) native "MathNatives_exp";
- static double _log(double value) native "MathNatives_log";
-}
diff --git a/runtime/lib/math_patch.dart b/runtime/lib/math_patch.dart
index 0612d3d..bfcbacc 100644
--- a/runtime/lib/math_patch.dart
+++ b/runtime/lib/math_patch.dart
@@ -3,17 +3,35 @@
// BSD-style license that can be found in the LICENSE file.
// A VM patch of the dart:math library.
-patch num pow(num x, num exponent) => MathNatives.pow(x, exponent);
-patch double atan2(num a, num b) => MathNatives.atan2(a, b);
-patch double sin(num x) => MathNatives.sin(x);
-patch double cos(num x) => MathNatives.cos(x);
-patch double tan(num x) => MathNatives.tan(x);
-patch double acos(num x) => MathNatives.acos(x);
-patch double asin(num x) => MathNatives.asin(x);
-patch double atan(num x) => MathNatives.atan(x);
-patch double sqrt(num x) => MathNatives.sqrt(x);
-patch double exp(num x) => MathNatives.exp(x);
-patch double log(num x) => MathNatives.log(x);
+patch num pow(num x, num exponent) {
+ if (exponent is int) {
+ return x.pow(exponent);
+ }
+ // Double.pow will call exponent.toDouble().
+ return x.toDouble().pow(exponent);
+}
+
+patch double atan2(num a, num b) => _atan2(a.toDouble(), b.toDouble());
+patch double sin(num value) => _sin(value.toDouble());
+patch double cos(num value) => _cos(value.toDouble());
+patch double tan(num value) => _tan(value.toDouble());
+patch double acos(num value) => _acos(value.toDouble());
+patch double asin(num value) => _asin(value.toDouble());
+patch double atan(num value) => _atan(value.toDouble());
+patch double sqrt(num value) => _sqrt(value.toDouble());
+patch double exp(num value) => _exp(value.toDouble());
+patch double log(num value) => _log(value.toDouble());
+
+double _atan2(double a, double b) native "Math_atan2";
+double _sin(double x) native "Math_sin";
+double _cos(double x) native "Math_cos";
+double _tan(double x) native "Math_tan";
+double _acos(double x) native "Math_acos";
+double _asin(double x) native "Math_asin";
+double _atan(double x) native "Math_atan";
+double _sqrt(double x) native "Math_sqrt";
+double _exp(double x) native "Math_exp";
+double _log(double x) native "Math_log";
// TODO(iposva): Handle patch methods within a patch class correctly.
@@ -33,20 +51,24 @@
class _Random implements Random {
// Internal state of the random number generator.
- var _state_lo;
- var _state_hi;
+ var _state;
+ static const kSTATE_LO = 0;
+ static const kSTATE_HI = 1;
- _Random._internal(state)
- : _state_lo = (state & _MASK_32), _state_hi = (state >> 32);
+ _Random._internal(state) {
+ _state = new List(2);
+ _state[kSTATE_LO] = state & _MASK_32;
+ _state[kSTATE_HI] = state >> 32;
+ }
// The algorithm used here is Multiply with Carry (MWC) with a Base b = 2^32.
// http://en.wikipedia.org/wiki/Multiply-with-carry
// The constant A is selected from "Numerical Recipes 3rd Edition" p.348 B1.
int _nextInt32() {
- var state = ((_A * (_state_lo)) + _state_hi) & _MASK_64;
- _state_lo = state & _MASK_32;
- _state_hi = state >> 32;
- return _state_lo;
+ var state = ((_A * (_state[kSTATE_LO])) + _state[kSTATE_HI]) & _MASK_64;
+ _state[kSTATE_LO] = state & _MASK_32;
+ _state[kSTATE_HI] = state >> 32;
+ return _state[kSTATE_LO];
}
int nextInt(int max) {
diff --git a/runtime/lib/math_sources.gypi b/runtime/lib/math_sources.gypi
index 5fb0d9e..2a18173 100644
--- a/runtime/lib/math_sources.gypi
+++ b/runtime/lib/math_sources.gypi
@@ -4,6 +4,7 @@
{
'sources': [
+ 'math.cc',
'math_patch.dart',
],
}
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index 3d9ed92..6f1fef5 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -22,14 +22,8 @@
Instance::CheckedHandle(arguments->NativeArgAt(0));
GET_NATIVE_ARGUMENT(String, function_name, arguments->NativeArgAt(1));
GET_NATIVE_ARGUMENT(Array, func_args, arguments->NativeArgAt(2));
- if (instance.IsNull()) {
- GrowableArray<const Object*> args;
- args.Add(&function_name);
- args.Add(&func_args);
- Exceptions::ThrowByType(Exceptions::kNullPointer, args);
- }
const Object& null_object = Object::Handle(Object::null());
- GrowableArray<const Object*> dart_arguments(3);
+ GrowableArray<const Object*> dart_arguments(4);
dart_arguments.Add(&instance);
dart_arguments.Add(&function_name);
dart_arguments.Add(&func_args);
diff --git a/runtime/lib/regexp.cc b/runtime/lib/regexp.cc
index 00088b5..969d5ff 100644
--- a/runtime/lib/regexp.cc
+++ b/runtime/lib/regexp.cc
@@ -12,19 +12,9 @@
namespace dart {
-static void CheckAndThrowExceptionIfNull(const Instance& obj) {
- if (obj.IsNull()) {
- GrowableArray<const Object*> args;
- Exceptions::ThrowByType(Exceptions::kNullPointer, args);
- }
-}
-
-
DEFINE_NATIVE_ENTRY(JSSyntaxRegExp_factory, 4) {
ASSERT(AbstractTypeArguments::CheckedHandle(
arguments->NativeArgAt(0)).IsNull());
- const Instance& arg1 = Instance::CheckedHandle(arguments->NativeArgAt(1));
- CheckAndThrowExceptionIfNull(arg1);
GET_NATIVE_ARGUMENT(String, pattern, arguments->NativeArgAt(1));
GET_NATIVE_ARGUMENT(Instance, handle_multi_line, arguments->NativeArgAt(2));
GET_NATIVE_ARGUMENT(Instance, handle_ignore_case, arguments->NativeArgAt(3));
@@ -75,8 +65,6 @@
DEFINE_NATIVE_ENTRY(JSSyntaxRegExp_ExecuteMatch, 3) {
const JSRegExp& regexp = JSRegExp::CheckedHandle(arguments->NativeArgAt(0));
ASSERT(!regexp.IsNull());
- const Instance& arg1 = Instance::CheckedHandle(arguments->NativeArgAt(1));
- CheckAndThrowExceptionIfNull(arg1);
GET_NATIVE_ARGUMENT(String, str, arguments->NativeArgAt(1));
GET_NATIVE_ARGUMENT(Smi, start_index, arguments->NativeArgAt(2));
return Jscre::Execute(regexp, str, start_index.Value());
diff --git a/runtime/lib/regexp_patch.dart b/runtime/lib/regexp_patch.dart
index d6e830c..6a921fa 100644
--- a/runtime/lib/regexp_patch.dart
+++ b/runtime/lib/regexp_patch.dart
@@ -77,6 +77,7 @@
}
Iterable<Match> allMatches(String str) {
+ if (str is! String) throw new ArgumentError(str);
List<Match> result = new List<Match>();
int length = str.length;
int startIndex = 0;
diff --git a/runtime/lib/string.cc b/runtime/lib/string.cc
index 76c097a..797cad2 100644
--- a/runtime/lib/string.cc
+++ b/runtime/lib/string.cc
@@ -20,7 +20,7 @@
// Unbox the array and determine the maximum element width.
bool is_one_byte_string = true;
intptr_t utf16_len = array_len;
- uint32_t* utf32_array = zone->Alloc<uint32_t>(array_len);
+ int32_t* utf32_array = zone->Alloc<int32_t>(array_len);
Object& index_object = Object::Handle(isolate);
for (intptr_t i = 0; i < array_len; i++) {
index_object = a.At(i);
@@ -102,7 +102,7 @@
GET_NATIVE_ARGUMENT(Integer, index, arguments->NativeArgAt(1));
uint32_t value = StringValueAt(receiver, index);
ASSERT(value <= 0x10FFFF);
- return Symbols::New(&value, 1);
+ return Symbols::FromCharCode(value);
}
DEFINE_NATIVE_ENTRY(String_charCodeAt, 2) {
@@ -144,10 +144,6 @@
Instance& elem = Instance::Handle();
for (intptr_t i = 0; i < strings.Length(); i++) {
elem ^= strings.At(i);
- if (elem.IsNull()) {
- GrowableArray<const Object*> args;
- Exceptions::ThrowByType(Exceptions::kNullPointer, args);
- }
if (!elem.IsString()) {
GrowableArray<const Object*> args;
args.Add(&elem);
diff --git a/runtime/tests/vm/dart/isolate_mirror_local_test.dart b/runtime/tests/vm/dart/isolate_mirror_local_test.dart
index 821912b..d4b8b88 100644
--- a/runtime/tests/vm/dart/isolate_mirror_local_test.dart
+++ b/runtime/tests/vm/dart/isolate_mirror_local_test.dart
@@ -304,9 +304,8 @@
Expect.equals('dart:core.List', list_intf.qualifiedName);
Expect.isFalse(list_intf.isPrivate);
Expect.equals('Object', list_intf.superclass.simpleName);
- Expect.equals('_ListImpl', list_intf.defaultFactory.simpleName);
Expect.equals('dart:core', list_intf.owner.simpleName);
- Expect.isFalse(list_intf.isClass);
+ Expect.isTrue(list_intf.isClass);
Expect.equals('Collection', list_intf.superinterfaces[0].simpleName);
Expect.equals("ClassMirror on 'List'", list_intf.toString());
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 5f2ec21..9b8ab80 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -5,6 +5,8 @@
# When a spawned isolate throws an uncaught exception, we terminate the vm.
cc/RunLoop_ExceptionChild: Fail
+cc/SymbolUnicode: Fail
+
# These tests are expected to crash on all platforms.
cc/ArrayNew_Overflow_Crash: Crash
cc/AllocGeneric_Overflow: Crash
diff --git a/runtime/tools/gyp/nss_configurations.gypi b/runtime/tools/gyp/nss_configurations.gypi
index 2897c6c..74c857c 100644
--- a/runtime/tools/gyp/nss_configurations.gypi
+++ b/runtime/tools/gyp/nss_configurations.gypi
@@ -37,9 +37,6 @@
'-Werror',
'-Wall',
'-ansi',
- # This flag would let a certain assembly function be inlined,
- # causing errors in mpcpucache.c.
- '-fvisibility=hidden',
# Not supported for C, only for C++.
'-Wnon-virtual-dtor',
'-Wno-conversion-null',
diff --git a/runtime/vm/assembler_ia32.cc b/runtime/vm/assembler_ia32.cc
index ec7f4c1..7fa7e21 100644
--- a/runtime/vm/assembler_ia32.cc
+++ b/runtime/vm/assembler_ia32.cc
@@ -19,15 +19,16 @@
DEFINE_FLAG(bool, use_sse41, true, "Use SSE 4.1 if available");
-bool CPUFeatures::sse3_supported_ = false;
+bool CPUFeatures::sse2_supported_ = false;
bool CPUFeatures::sse4_1_supported_ = false;
#ifdef DEBUG
bool CPUFeatures::initialized_ = false;
#endif
-bool CPUFeatures::sse3_supported() {
+
+bool CPUFeatures::sse2_supported() {
DEBUG_ASSERT(initialized_);
- return sse3_supported_;
+ return sse2_supported_;
}
@@ -60,7 +61,7 @@
typedef uint64_t (*DetectCPUFeatures)();
uint64_t features =
reinterpret_cast<DetectCPUFeatures>(instructions.EntryPoint())();
- sse3_supported_ = (features & kSSE3BitMask) != 0;
+ sse2_supported_ = (features & kSSE2BitMask) != 0;
sse4_1_supported_ = (features & kSSE4_1BitMask) != 0;
#ifdef DEBUG
initialized_ = true;
diff --git a/runtime/vm/assembler_ia32.h b/runtime/vm/assembler_ia32.h
index 5d80c8b..a738df3 100644
--- a/runtime/vm/assembler_ia32.h
+++ b/runtime/vm/assembler_ia32.h
@@ -258,14 +258,14 @@
class CPUFeatures : public AllStatic {
public:
static void InitOnce();
- static bool sse3_supported();
+ static bool sse2_supported();
static bool sse4_1_supported();
private:
- static const uint64_t kSSE3BitMask = static_cast<uint64_t>(1) << 32;
+ static const uint64_t kSSE2BitMask = static_cast<uint64_t>(1) << 26;
static const uint64_t kSSE4_1BitMask = static_cast<uint64_t>(1) << 51;
- static bool sse3_supported_;
+ static bool sse2_supported_;
static bool sse4_1_supported_;
#ifdef DEBUG
static bool initialized_;
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index 373925e..57ffd01 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -19,18 +19,11 @@
DEFINE_FLAG(bool, use_sse41, true, "Use SSE 4.1 if available");
-bool CPUFeatures::sse3_supported_ = false;
bool CPUFeatures::sse4_1_supported_ = false;
#ifdef DEBUG
bool CPUFeatures::initialized_ = false;
#endif
-bool CPUFeatures::sse3_supported() {
- DEBUG_ASSERT(initialized_);
- return sse3_supported_;
-}
-
-
bool CPUFeatures::sse4_1_supported() {
DEBUG_ASSERT(initialized_);
return sse4_1_supported_ && FLAG_use_sse41;
@@ -63,7 +56,6 @@
typedef uint64_t (*DetectCPUFeatures)();
uint64_t features =
reinterpret_cast<DetectCPUFeatures>(instructions.EntryPoint())();
- sse3_supported_ = (features & kSSE3BitMask) != 0;
sse4_1_supported_ = (features & kSSE4_1BitMask) != 0;
#ifdef DEBUG
initialized_ = true;
@@ -395,11 +387,10 @@
void Assembler::movss(XmmRegister dst, const Address& src) {
- // TODO(srdjan): implement and test XMM8 - XMM15.
- ASSERT(dst <= XMM7);
+ ASSERT(dst <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF3);
- EmitOperandREX(0, src, REX_NONE);
+ EmitREX_RB(dst, src);
EmitUint8(0x0F);
EmitUint8(0x10);
EmitOperand(dst & 7, src);
@@ -407,11 +398,10 @@
void Assembler::movss(const Address& dst, XmmRegister src) {
- // TODO(srdjan): implement and test XMM8 - XMM15.
- ASSERT(src <= XMM7);
+ ASSERT(src <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF3);
- EmitOperandREX(0, dst, REX_NONE);
+ EmitREX_RB(src, dst);
EmitUint8(0x0F);
EmitUint8(0x11);
EmitOperand(src & 7, dst);
@@ -419,11 +409,11 @@
void Assembler::movss(XmmRegister dst, XmmRegister src) {
- // TODO(srdjan): implement and test XMM8 - XMM15.
- ASSERT(src <= XMM7);
- ASSERT(dst <= XMM7);
+ ASSERT(src <= XMM15);
+ ASSERT(dst <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF3);
+ EmitREX_RB(src, dst);
EmitUint8(0x0F);
EmitUint8(0x11);
EmitXmmRegisterOperand(src & 7, dst);
@@ -431,9 +421,10 @@
void Assembler::movd(XmmRegister dst, Register src) {
- ASSERT(dst <= XMM7);
+ ASSERT(dst <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x66);
+ EmitREX_RB(dst, src);
EmitUint8(0x0F);
EmitUint8(0x6E);
EmitOperand(dst & 7, Operand(src));
@@ -441,9 +432,10 @@
void Assembler::movd(Register dst, XmmRegister src) {
- ASSERT(src <= XMM7);
+ ASSERT(src <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x66);
+ EmitREX_RB(src, dst);
EmitUint8(0x0F);
EmitUint8(0x7E);
EmitOperand(src & 7, Operand(dst));
@@ -451,59 +443,58 @@
void Assembler::addss(XmmRegister dst, XmmRegister src) {
- // TODO(srdjan): implement and test XMM8 - XMM15.
- ASSERT(src <= XMM7);
- ASSERT(dst <= XMM7);
+ ASSERT(src <= XMM15);
+ ASSERT(dst <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF3);
+ EmitREX_RB(dst, src);
EmitUint8(0x0F);
EmitUint8(0x58);
- EmitXmmRegisterOperand(dst, src);
+ EmitXmmRegisterOperand(dst & 7, src);
}
void Assembler::subss(XmmRegister dst, XmmRegister src) {
- // TODO(srdjan): implement and test XMM8 - XMM15.
- ASSERT(src <= XMM7);
- ASSERT(dst <= XMM7);
+ ASSERT(src <= XMM15);
+ ASSERT(dst <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF3);
+ EmitREX_RB(dst, src);
EmitUint8(0x0F);
EmitUint8(0x5C);
- EmitXmmRegisterOperand(dst, src);
+ EmitXmmRegisterOperand(dst & 7, src);
}
void Assembler::mulss(XmmRegister dst, XmmRegister src) {
- // TODO(srdjan): implement and test XMM8 - XMM15.
- ASSERT(src <= XMM7);
- ASSERT(dst <= XMM7);
+ ASSERT(src <= XMM15);
+ ASSERT(dst <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF3);
+ EmitREX_RB(dst, src);
EmitUint8(0x0F);
EmitUint8(0x59);
- EmitXmmRegisterOperand(dst, src);
+ EmitXmmRegisterOperand(dst & 7, src);
}
void Assembler::divss(XmmRegister dst, XmmRegister src) {
- // TODO(srdjan): implement and test XMM8 - XMM15.
- ASSERT(src <= XMM7);
- ASSERT(dst <= XMM7);
+ ASSERT(src <= XMM15);
+ ASSERT(dst <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF3);
+ EmitREX_RB(dst, src);
EmitUint8(0x0F);
EmitUint8(0x5E);
- EmitXmmRegisterOperand(dst, src);
+ EmitXmmRegisterOperand(dst & 7, src);
}
void Assembler::movsd(XmmRegister dst, const Address& src) {
- // TODO(srdjan): implement and test XMM8 - XMM15.
- ASSERT(dst <= XMM7);
+ ASSERT(dst <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF2);
- EmitOperandREX(0, src, REX_NONE);
+ EmitREX_RB(dst, src);
EmitUint8(0x0F);
EmitUint8(0x10);
EmitOperand(dst & 7, src);
@@ -511,11 +502,10 @@
void Assembler::movsd(const Address& dst, XmmRegister src) {
- // TODO(srdjan): implement and test XMM8 - XMM15.
- ASSERT(src <= XMM7);
+ ASSERT(src <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF2);
- EmitOperandREX(0, dst, REX_NONE);
+ EmitREX_RB(src, dst);
EmitUint8(0x0F);
EmitUint8(0x11);
EmitOperand(src & 7, dst);
@@ -523,11 +513,11 @@
void Assembler::movsd(XmmRegister dst, XmmRegister src) {
- // TODO(srdjan): implement and test XMM8 - XMM15.
- ASSERT(src <= XMM7);
- ASSERT(dst <= XMM7);
+ ASSERT(src <= XMM15);
+ ASSERT(dst <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF2);
+ EmitREX_RB(src, dst);
EmitUint8(0x0F);
EmitUint8(0x11);
EmitXmmRegisterOperand(src & 7, dst);
@@ -535,10 +525,10 @@
void Assembler::movaps(XmmRegister dst, XmmRegister src) {
- // TODO(vegorov): implement and test XMM8 - XMM15.
- ASSERT(src <= XMM7);
- ASSERT(dst <= XMM7);
+ ASSERT(src <= XMM15);
+ ASSERT(dst <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, src);
EmitUint8(0x0F);
EmitUint8(0x28);
EmitXmmRegisterOperand(dst & 7, src);
@@ -546,90 +536,93 @@
void Assembler::addsd(XmmRegister dst, XmmRegister src) {
- // TODO(srdjan): implement and test XMM8 - XMM15.
- ASSERT(src <= XMM7);
- ASSERT(dst <= XMM7);
+ ASSERT(src <= XMM15);
+ ASSERT(dst <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF2);
+ EmitREX_RB(dst, src);
EmitUint8(0x0F);
EmitUint8(0x58);
- EmitXmmRegisterOperand(dst, src);
+ EmitXmmRegisterOperand(dst & 7, src);
}
void Assembler::subsd(XmmRegister dst, XmmRegister src) {
- // TODO(srdjan): implement and test XMM8 - XMM15.
- ASSERT(src <= XMM7);
- ASSERT(dst <= XMM7);
+ ASSERT(src <= XMM15);
+ ASSERT(dst <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF2);
+ EmitREX_RB(dst, src);
EmitUint8(0x0F);
EmitUint8(0x5C);
- EmitXmmRegisterOperand(dst, src);
+ EmitXmmRegisterOperand(dst & 7, src);
}
void Assembler::mulsd(XmmRegister dst, XmmRegister src) {
- // TODO(srdjan): implement and test XMM8 - XMM15.
- ASSERT(src <= XMM7);
- ASSERT(dst <= XMM7);
+ ASSERT(src <= XMM15);
+ ASSERT(dst <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF2);
+ EmitREX_RB(dst, src);
EmitUint8(0x0F);
EmitUint8(0x59);
- EmitXmmRegisterOperand(dst, src);
+ EmitXmmRegisterOperand(dst & 7, src);
}
void Assembler::divsd(XmmRegister dst, XmmRegister src) {
- // TODO(srdjan): implement and test XMM8 - XMM15.
- ASSERT(src <= XMM7);
- ASSERT(dst <= XMM7);
+ ASSERT(src <= XMM15);
+ ASSERT(dst <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF2);
+ EmitREX_RB(dst, src);
EmitUint8(0x0F);
EmitUint8(0x5E);
- EmitXmmRegisterOperand(dst, src);
+ EmitXmmRegisterOperand(dst & 7, src);
}
void Assembler::comisd(XmmRegister a, XmmRegister b) {
- ASSERT(a <= XMM7);
- ASSERT(b <= XMM7);
+ ASSERT(a <= XMM15);
+ ASSERT(b <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x66);
+ EmitREX_RB(a, b);
EmitUint8(0x0F);
EmitUint8(0x2F);
- EmitXmmRegisterOperand(a, b);
+ EmitXmmRegisterOperand(a & 7, b);
}
void Assembler::movmskpd(Register dst, XmmRegister src) {
- ASSERT(src <= XMM7);
+ ASSERT(src <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x66);
+ EmitREX_RB(dst, src);
EmitUint8(0x0F);
EmitUint8(0x50);
- EmitXmmRegisterOperand(dst, src);
+ EmitXmmRegisterOperand(dst & 7, src);
}
void Assembler::sqrtsd(XmmRegister dst, XmmRegister src) {
- ASSERT(dst <= XMM7);
- ASSERT(src <= XMM7);
+ ASSERT(dst <= XMM15);
+ ASSERT(src <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF2);
+ EmitREX_RB(dst, src);
EmitUint8(0x0F);
EmitUint8(0x51);
- EmitXmmRegisterOperand(dst, src);
+ EmitXmmRegisterOperand(dst & 7, src);
}
void Assembler::xorpd(XmmRegister dst, const Address& src) {
- ASSERT(dst <= XMM7);
+ ASSERT(dst <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x66);
- EmitOperandREX(0, src, REX_NONE);
+ EmitOperandREX(dst, src, REX_NONE);
EmitUint8(0x0F);
EmitUint8(0x57);
EmitOperand(dst & 7, src);
@@ -637,59 +630,62 @@
void Assembler::xorpd(XmmRegister dst, XmmRegister src) {
- ASSERT(dst <= XMM7);
- ASSERT(src <= XMM7);
+ ASSERT(dst <= XMM15);
+ ASSERT(src <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x66);
+ EmitREX_RB(dst, src);
EmitUint8(0x0F);
EmitUint8(0x57);
- EmitXmmRegisterOperand(dst, src);
+ EmitXmmRegisterOperand(dst & 7, src);
}
void Assembler::cvtsi2sd(XmmRegister dst, Register src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
- ASSERT(dst <= XMM7);
+ ASSERT(dst <= XMM15);
Operand operand(src);
EmitUint8(0xF2);
- EmitOperandREX(0, operand, REX_W);
+ EmitOperandREX(dst, operand, REX_W);
EmitUint8(0x0F);
EmitUint8(0x2A);
- EmitOperand(dst, operand);
+ EmitOperand(dst & 7, operand);
}
void Assembler::cvttsd2siq(Register dst, XmmRegister src) {
- ASSERT(src <= XMM7);
+ ASSERT(src <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF2);
Operand operand(dst);
- EmitOperandREX(0, operand, REX_W);
+ EmitREX_RB(dst, src, REX_W);
EmitUint8(0x0F);
EmitUint8(0x2C);
- EmitXmmRegisterOperand(dst, src);
+ EmitXmmRegisterOperand(dst & 7, src);
}
void Assembler::cvtss2sd(XmmRegister dst, XmmRegister src) {
- ASSERT(src <= XMM7);
- ASSERT(dst <= XMM7);
+ ASSERT(src <= XMM15);
+ ASSERT(dst <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF3);
+ EmitREX_RB(dst, src);
EmitUint8(0x0F);
EmitUint8(0x5A);
- EmitXmmRegisterOperand(dst, src);
+ EmitXmmRegisterOperand(dst & 7, src);
}
void Assembler::cvtsd2ss(XmmRegister dst, XmmRegister src) {
- ASSERT(src <= XMM7);
- ASSERT(dst <= XMM7);
+ ASSERT(src <= XMM15);
+ ASSERT(dst <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF2);
+ EmitREX_RB(dst, src);
EmitUint8(0x0F);
EmitUint8(0x5A);
- EmitXmmRegisterOperand(dst, src);
+ EmitXmmRegisterOperand(dst & 7, src);
}
@@ -2107,7 +2103,8 @@
static const char* xmm_reg_names[kNumberOfXmmRegisters] = {
- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
+ "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
+ "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
};
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index cebc865..ab97b2a 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -275,14 +275,13 @@
class CPUFeatures : public AllStatic {
public:
static void InitOnce();
- static bool sse3_supported();
+ // x64 always has at least SSE2.
+ static bool sse2_supported() { return true; }
static bool sse4_1_supported();
private:
- static const uint64_t kSSE3BitMask = static_cast<uint64_t>(1) << 32;
static const uint64_t kSSE4_1BitMask = static_cast<uint64_t>(1) << 51;
- static bool sse3_supported_;
static bool sse4_1_supported_;
#ifdef DEBUG
static bool initialized_;
@@ -678,7 +677,18 @@
inline void EmitXmmRegisterOperand(int rm, XmmRegister reg);
inline void EmitFixup(AssemblerFixup* fixup);
inline void EmitOperandSizeOverride();
-
+ inline void EmitREX_RB(XmmRegister reg,
+ XmmRegister base,
+ uint8_t rex = REX_NONE);
+ inline void EmitREX_RB(XmmRegister reg,
+ const Operand& operand,
+ uint8_t rex = REX_NONE);
+ inline void EmitREX_RB(XmmRegister reg,
+ Register base,
+ uint8_t rex = REX_NONE);
+ inline void EmitREX_RB(Register reg,
+ XmmRegister base,
+ uint8_t rex = REX_NONE);
void EmitOperand(int rm, const Operand& operand);
void EmitImmediate(const Immediate& imm);
void EmitComplex(int rm, const Operand& operand, const Immediate& immediate);
@@ -726,6 +736,42 @@
}
+inline void Assembler::EmitREX_RB(XmmRegister reg,
+ XmmRegister base,
+ uint8_t rex) {
+ if (reg > 7) rex |= REX_R;
+ if (base > 7) rex |= REX_B;
+ if (rex != REX_NONE) EmitUint8(REX_PREFIX | rex);
+}
+
+
+inline void Assembler::EmitREX_RB(XmmRegister reg,
+ const Operand& operand,
+ uint8_t rex) {
+ if (reg > 7) rex |= REX_R;
+ rex |= operand.rex();
+ if (rex != REX_NONE) EmitUint8(REX_PREFIX | rex);
+}
+
+
+inline void Assembler::EmitREX_RB(XmmRegister reg,
+ Register base,
+ uint8_t rex) {
+ if (reg > 7) rex |= REX_R;
+ if (base > 7) rex |= REX_B;
+ if (rex != REX_NONE) EmitUint8(REX_PREFIX | rex);
+}
+
+
+inline void Assembler::EmitREX_RB(Register reg,
+ XmmRegister base,
+ uint8_t rex) {
+ if (reg > 7) rex |= REX_R;
+ if (base > 7) rex |= REX_B;
+ if (rex != REX_NONE) EmitUint8(REX_PREFIX | rex);
+}
+
+
inline void Assembler::EmitFixup(AssemblerFixup* fixup) {
buffer_.EmitFixup(fixup);
}
diff --git a/runtime/vm/assembler_x64_test.cc b/runtime/vm/assembler_x64_test.cc
index f2d6fce..32a54fa 100644
--- a/runtime/vm/assembler_x64_test.cc
+++ b/runtime/vm/assembler_x64_test.cc
@@ -1244,6 +1244,14 @@
__ movss(XMM5, XMM4);
__ movss(XMM6, XMM5);
__ movss(XMM7, XMM6);
+ __ movss(XMM8, XMM7);
+ __ movss(XMM9, XMM8);
+ __ movss(XMM10, XMM9);
+ __ movss(XMM11, XMM10);
+ __ movss(XMM12, XMM11);
+ __ movss(XMM13, XMM12);
+ __ movss(XMM14, XMM13);
+ __ movss(XMM15, XMM14);
__ pushq(R15); // Callee saved.
__ pushq(RAX);
__ movq(Address(RSP, 0), Immediate(0));
@@ -1258,8 +1266,23 @@
__ movss(XMM3, Address(R15, 0));
__ movq(RAX, RSP);
__ movss(Address(RAX, 0), XMM3);
- __ movss(XMM4, Address(RAX, 0));
- __ movss(XMM0, Address(RAX, 0));
+ __ movss(XMM1, Address(RAX, 0));
+ __ movss(XMM15, Address(RAX, 0));
+ __ movss(XMM14, XMM15);
+ __ movss(XMM13, XMM14);
+ __ movss(XMM12, XMM13);
+ __ movss(XMM11, XMM12);
+ __ movss(XMM10, XMM11);
+ __ movss(XMM9, XMM10);
+ __ movss(XMM8, XMM9);
+ __ movss(XMM7, XMM8);
+ __ movss(XMM6, XMM7);
+ __ movss(XMM5, XMM6);
+ __ movss(XMM4, XMM5);
+ __ movss(XMM3, XMM4);
+ __ movss(XMM2, XMM3);
+ __ movss(XMM1, XMM2);
+ __ movss(XMM0, XMM1);
__ popq(RAX);
__ popq(R15); // Callee saved.
__ ret();
@@ -1275,12 +1298,18 @@
ASSEMBLER_TEST_GENERATE(SingleFPMoves2, assembler) {
__ movq(RAX, Immediate(bit_cast<int32_t, float>(234.0f)));
__ movd(XMM0, RAX);
- __ movss(XMM1, XMM0);
+ __ movd(XMM8, RAX);
+ __ movss(XMM1, XMM8);
__ pushq(RAX);
__ movq(Address(RSP, 0), Immediate(0));
__ movss(XMM0, Address(RSP, 0));
__ movss(Address(RSP, 0), XMM1);
__ movss(XMM0, Address(RSP, 0));
+ __ movq(Address(RSP, 0), Immediate(0));
+ __ movss(XMM9, XMM8);
+ __ movss(Address(RSP, 0), XMM9);
+ __ movss(XMM8, Address(RSP, 0));
+ __ movss(XMM0, XMM8);
__ popq(RAX);
__ ret();
}
@@ -1297,12 +1326,19 @@
__ pushq(RCX);
__ movq(RBX, Immediate(bit_cast<int32_t, float>(12.3f)));
__ movd(XMM0, RBX);
+ __ movd(XMM8, RBX);
__ movq(RCX, Immediate(bit_cast<int32_t, float>(3.4f)));
__ movd(XMM1, RCX);
+ __ movd(XMM9, RCX);
__ addss(XMM0, XMM1); // 15.7f
__ mulss(XMM0, XMM1); // 53.38f
__ subss(XMM0, XMM1); // 49.98f
__ divss(XMM0, XMM1); // 14.7f
+ __ addss(XMM8, XMM9); // 15.7f
+ __ mulss(XMM8, XMM9); // 53.38f
+ __ subss(XMM8, XMM9); // 49.98f
+ __ divss(XMM8, XMM9); // 14.7f
+ __ subss(XMM0, XMM8); // 0.0f
__ popq(RCX);
__ popq(RBX);
__ ret();
@@ -1312,7 +1348,7 @@
ASSEMBLER_TEST_RUN(SingleFPOperations, entry) {
typedef float (*SingleFPOperationsCode)();
float res = reinterpret_cast<SingleFPOperationsCode>(entry)();
- EXPECT_FLOAT_EQ(14.7f, res, 0.001f);
+ EXPECT_FLOAT_EQ(0.0f, res, 0.001f);
}
@@ -1328,9 +1364,17 @@
__ movsd(XMM5, XMM4);
__ movsd(XMM6, XMM5);
__ movsd(XMM7, XMM6);
+ __ movsd(XMM8, XMM7);
+ __ movsd(XMM9, XMM8);
+ __ movsd(XMM10, XMM9);
+ __ movsd(XMM11, XMM10);
+ __ movsd(XMM12, XMM11);
+ __ movsd(XMM13, XMM12);
+ __ movsd(XMM14, XMM13);
+ __ movsd(XMM15, XMM14);
__ movq(Address(RSP, 0), Immediate(0));
__ movsd(XMM0, Address(RSP, 0));
- __ movsd(Address(RSP, 0), XMM7);
+ __ movsd(Address(RSP, 0), XMM15);
__ movsd(XMM1, Address(RSP, 0));
__ movq(R10, RSP);
__ movsd(Address(R10, 0), XMM1);
@@ -1341,7 +1385,15 @@
__ movq(RAX, RSP);
__ movsd(Address(RAX, 0), XMM3);
__ movsd(XMM4, Address(RAX, 0));
- __ movsd(XMM7, Address(RSP, 0));
+ __ movsd(XMM15, Address(RSP, 0));
+ __ movaps(XMM14, XMM15);
+ __ movaps(XMM13, XMM14);
+ __ movaps(XMM12, XMM13);
+ __ movaps(XMM11, XMM12);
+ __ movaps(XMM10, XMM11);
+ __ movaps(XMM9, XMM10);
+ __ movaps(XMM8, XMM9);
+ __ movaps(XMM7, XMM8);
__ movaps(XMM6, XMM7);
__ movaps(XMM5, XMM6);
__ movaps(XMM4, XMM5);
@@ -1365,13 +1417,22 @@
__ movq(RAX, Immediate(bit_cast<int64_t, double>(12.3)));
__ pushq(RAX);
__ movsd(XMM0, Address(RSP, 0));
+ __ movsd(XMM8, Address(RSP, 0));
__ movq(RAX, Immediate(bit_cast<int64_t, double>(3.4)));
__ movq(Address(RSP, 0), RAX);
+ __ movsd(XMM12, Address(RSP, 0));
+ __ addsd(XMM8, XMM12); // 15.7
+ __ mulsd(XMM8, XMM12); // 53.38
+ __ subsd(XMM8, XMM12); // 49.98
+ __ divsd(XMM8, XMM12); // 14.7
+ __ sqrtsd(XMM8, XMM8); // 3.834
__ movsd(XMM1, Address(RSP, 0));
__ addsd(XMM0, XMM1); // 15.7
__ mulsd(XMM0, XMM1); // 53.38
__ subsd(XMM0, XMM1); // 49.98
__ divsd(XMM0, XMM1); // 14.7
+ __ sqrtsd(XMM0, XMM0); // 3.834057902
+ __ addsd(XMM0, XMM8); // 7.6681
__ popq(RAX);
__ ret();
}
@@ -1380,13 +1441,16 @@
ASSEMBLER_TEST_RUN(DoubleFPOperations, entry) {
typedef double (*SingleFPOperationsCode)();
double res = reinterpret_cast<SingleFPOperationsCode>(entry)();
- EXPECT_FLOAT_EQ(14.7, res, 0.001);
+ EXPECT_FLOAT_EQ(7.668, res, 0.001);
}
ASSEMBLER_TEST_GENERATE(Int32ToDoubleConversion, assembler) {
__ movl(RDX, Immediate(6));
__ cvtsi2sd(XMM0, RDX);
+ __ movl(RDX, Immediate(8));
+ __ cvtsi2sd(XMM8, RDX);
+ __ subsd(XMM0, XMM8);
__ ret();
}
@@ -1394,13 +1458,16 @@
ASSEMBLER_TEST_RUN(Int32ToDoubleConversion, entry) {
typedef double (*IntToDoubleConversionCode)();
double res = reinterpret_cast<IntToDoubleConversionCode>(entry)();
- EXPECT_FLOAT_EQ(6.0, res, 0.001);
+ EXPECT_FLOAT_EQ(-2.0, res, 0.001);
}
ASSEMBLER_TEST_GENERATE(Int64ToDoubleConversion, assembler) {
__ movq(RDX, Immediate(12LL << 32));
__ cvtsi2sd(XMM0, RDX);
+ __ movsd(XMM15, XMM0); // Move to high register
+ __ addsd(XMM0, XMM0); // Stomp XMM0
+ __ movsd(XMM0, XMM15); // Move back to XMM0
__ ret();
}
@@ -1415,9 +1482,14 @@
ASSEMBLER_TEST_GENERATE(DoubleToInt64Conversion, assembler) {
__ movq(RAX, Immediate(bit_cast<int64_t, double>(12.3)));
__ pushq(RAX);
+ __ movsd(XMM9, Address(RSP, 0));
__ movsd(XMM6, Address(RSP, 0));
__ popq(RAX);
+ __ cvttsd2siq(R10, XMM6);
__ cvttsd2siq(RDX, XMM6);
+ __ cvttsd2siq(R10, XMM9);
+ __ cvttsd2siq(RDX, XMM9);
+ __ subq(RDX, R10);
__ movq(RAX, RDX);
__ ret();
}
@@ -1426,7 +1498,7 @@
ASSEMBLER_TEST_RUN(DoubleToInt64Conversion, entry) {
typedef int64_t (*DoubleToInt64ConversionCode)();
int64_t res = reinterpret_cast<DoubleToInt64ConversionCode>(entry)();
- EXPECT_EQ(12, res);
+ EXPECT_EQ(0, res);
}
@@ -1605,7 +1677,14 @@
ASSEMBLER_TEST_GENERATE(XorpdZeroing2, assembler) {
+ Label done;
+ __ xorpd(XMM15, XMM15);
__ xorpd(XMM0, XMM0);
+ __ xorpd(XMM0, XMM15);
+ __ comisd(XMM0, XMM15);
+ __ j(ZERO, &done);
+ __ int3();
+ __ Bind(&done);
__ ret();
}
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index 29a2417..d719b0e 100644
--- a/runtime/vm/benchmark_test.cc
+++ b/runtime/vm/benchmark_test.cc
@@ -275,7 +275,7 @@
char* script = NULL;
if (dart_root != NULL) {
const char* kFormatStr =
- "#import('%s/sdk/lib/_internal/compiler/compiler.dart');";
+ "import '%s/sdk/lib/_internal/compiler/compiler.dart';";
intptr_t len = OS::SNPrint(NULL, 0, kFormatStr, dart_root) + 1;
script = reinterpret_cast<char*>(malloc(len));
EXPECT(script != NULL);
@@ -286,7 +286,7 @@
EXPECT_VALID(lib);
} else {
Dart_Handle lib = TestCase::LoadTestScript(
- "#import('sdk/lib/_internal/compiler/compiler.dart');",
+ "import 'sdk/lib/_internal/compiler/compiler.dart';",
reinterpret_cast<Dart_NativeEntryResolver>(NativeResolver));
EXPECT_VALID(lib);
}
diff --git a/runtime/vm/bootstrap_natives.cc b/runtime/vm/bootstrap_natives.cc
index 47a8c3a..9978bf7 100644
--- a/runtime/vm/bootstrap_natives.cc
+++ b/runtime/vm/bootstrap_natives.cc
@@ -60,7 +60,7 @@
ASSERT(!library.IsNull());
library.set_native_entry_resolver(resolver);
- library = Library::CollectionLibrary();
+ library = Library::MathLibrary();
ASSERT(!library.IsNull());
library.set_native_entry_resolver(resolver);
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 7b424b0..fad33c9 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -27,6 +27,7 @@
V(Integer_moduloFromInteger, 2) \
V(Integer_greaterThanFromInteger, 2) \
V(Integer_equalToInteger, 2) \
+ V(Integer_parse, 1) \
V(ReceivePortImpl_factory, 1) \
V(ReceivePortImpl_closeInternal, 1) \
V(SendPortImpl_sendInternal_, 3) \
@@ -55,6 +56,7 @@
V(Double_ceil, 1) \
V(Double_truncate, 1) \
V(Double_toInt, 1) \
+ V(Double_parse, 1) \
V(Double_toStringAsFixed, 2) \
V(Double_toStringAsExponential, 2) \
V(Double_toStringAsPrecision, 2) \
@@ -80,19 +82,16 @@
V(String_toLowerCase, 1) \
V(String_toUpperCase, 1) \
V(Strings_concatAll, 1) \
- V(MathNatives_sqrt, 1) \
- V(MathNatives_sin, 1) \
- V(MathNatives_cos, 1) \
- V(MathNatives_tan, 1) \
- V(MathNatives_asin, 1) \
- V(MathNatives_acos, 1) \
- V(MathNatives_atan, 1) \
- V(MathNatives_atan2, 2) \
- V(MathNatives_exp, 1) \
- V(MathNatives_log, 1) \
- V(MathNatives_random, 0) \
- V(MathNatives_parseInt, 1) \
- V(MathNatives_parseDouble, 1) \
+ V(Math_sqrt, 1) \
+ V(Math_sin, 1) \
+ V(Math_cos, 1) \
+ V(Math_tan, 1) \
+ V(Math_asin, 1) \
+ V(Math_acos, 1) \
+ V(Math_atan, 1) \
+ V(Math_atan2, 2) \
+ V(Math_exp, 1) \
+ V(Math_log, 1) \
V(DateNatives_currentTimeMillis, 0) \
V(DateNatives_timeZoneName, 1) \
V(DateNatives_timeZoneOffsetInSeconds, 1) \
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 3283db1..bae68fd 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -838,16 +838,6 @@
type_argument = arguments.TypeAt(i);
type_argument = FinalizeType(cls, type_argument, finalization);
if (type_argument.IsMalformed()) {
- // Malformed type arguments to a constructor of a generic type are
- // reported as a compile-time error.
- if (finalization >= kCanonicalizeForCreation) {
- const Script& script = Script::Handle(cls.script());
- const String& type_name =
- String::Handle(parameterized_type.UserVisibleName());
- ReportError(script, parameterized_type.token_pos(),
- "type '%s' has malformed type argument",
- type_name.ToCString());
- }
// In production mode, malformed type arguments are mapped to dynamic.
// In checked mode, a type with malformed type arguments is malformed.
if (FLAG_enable_type_checks || FLAG_error_on_malformed_type) {
@@ -877,7 +867,7 @@
// However, type parameter bounds are checked below, even for a raw type.
if (!arguments.IsNull() && (arguments.Length() != num_type_parameters)) {
// Wrong number of type arguments. The type is malformed.
- if (finalization >= kCanonicalizeForCreation) {
+ if (finalization >= kCanonicalizeExpression) {
const Script& script = Script::Handle(cls.script());
const String& type_name =
String::Handle(parameterized_type.UserVisibleName());
diff --git a/runtime/vm/class_finalizer.h b/runtime/vm/class_finalizer.h
index 18ce755..2fe9ea6 100644
--- a/runtime/vm/class_finalizer.h
+++ b/runtime/vm/class_finalizer.h
@@ -33,10 +33,13 @@
kDoNotResolve, // Type resolution is postponed.
kTryResolve, // Type resolution is attempted.
kFinalize, // Type resolution and type finalization are
- // required; a malformed type is tolerated.
+ // required; a malformed type is tolerated, since
+ // the type may be used as a type annotation.
kCanonicalize, // Same as kFinalize, but with canonicalization.
- kCanonicalizeForCreation, // Same as kCanonicalize, but do not tolerate
- // wrong number of type arguments.
+ kCanonicalizeExpression, // Same as kCanonicalize, but do not tolerate
+ // wrong number of type arguments or ambiguous
+ // type reference, since the type is not used as
+ // a type annotation, but as a type expression.
kCanonicalizeWellFormed // Error-free resolution, finalization, and
// canonicalization are required; a malformed
// type is not tolerated.
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index 008673f..f24bd03 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -770,73 +770,38 @@
}
-static bool UpdateResolvedStaticCall(const Code& code,
- intptr_t offset,
- const Code& target_code) {
- // PC offsets are mapped to the corresponding code object in the
- // resolved_static_calls array. The array grows as static calls are being
- // resolved.
- const int kOffset = 0;
- const int kCode = 1;
- const int kEntrySize = 2;
-
- GrowableObjectArray& resolved_static_calls =
- GrowableObjectArray::Handle(code.resolved_static_calls());
- intptr_t index = -1;
- if (resolved_static_calls.IsNull()) {
- resolved_static_calls = GrowableObjectArray::New(2, Heap::kOld);
- code.set_resolved_static_calls(resolved_static_calls);
- } else {
- // Search for the offset in the resolved static calls.
- const intptr_t len = resolved_static_calls.Length();
- Object& off = Object::Handle();
- for (intptr_t i = 0; i < len; i += kEntrySize) {
- off = resolved_static_calls.At(i + kOffset);
- if (Smi::Cast(off).Value() == offset) {
- index = i;
- break;
- }
- }
- }
- if (index == -1) {
- // The static call with this offset is not yet present: Add it.
- resolved_static_calls.Add(Smi::Handle(Smi::New(offset)));
- resolved_static_calls.Add(target_code);
- } else {
- // Overwrite the currently recorded target.
- resolved_static_calls.SetAt(index + kCode, target_code);
- }
- return index != -1;
-}
-
-
+// Patches static call with the target's entry point. Compiles target if
+// necessary.
DEFINE_RUNTIME_ENTRY(PatchStaticCall, 0) {
- // This function is called after successful resolving and compilation of
- // the target method.
ASSERT(arguments.ArgCount() == kPatchStaticCallRuntimeEntry.argument_count());
DartFrameIterator iterator;
StackFrame* caller_frame = iterator.NextFrame();
ASSERT(caller_frame != NULL);
- uword target = 0;
- Function& target_function = Function::Handle();
- CodePatcher::GetStaticCallAt(caller_frame->pc(), &target_function, &target);
- ASSERT(target_function.HasCode());
+ const Code& caller_code = Code::Handle(caller_frame->LookupDartCode());
+ ASSERT(!caller_code.IsNull());
+ const Function& target_function = Function::Handle(
+ caller_code.GetStaticCallTargetFunctionAt(caller_frame->pc()));
+ if (!target_function.HasCode()) {
+ const Error& error =
+ Error::Handle(Compiler::CompileFunction(target_function));
+ if (!error.IsNull()) {
+ Exceptions::PropagateError(error);
+ }
+ }
const Code& target_code = Code::Handle(target_function.CurrentCode());
- uword new_target = target_code.EntryPoint();
- // Verify that we are not patching repeatedly.
- ASSERT(target != new_target);
- CodePatcher::PatchStaticCallAt(caller_frame->pc(), new_target);
- const Code& code = Code::Handle(caller_frame->LookupDartCode());
- bool found = UpdateResolvedStaticCall(code,
- caller_frame->pc() - code.EntryPoint(),
- target_code);
- ASSERT(!found);
+ // Before patching verify that we are not repeatedly patching to the same
+ // target.
+ ASSERT(target_code.EntryPoint() !=
+ CodePatcher::GetStaticCallTargetAt(caller_frame->pc()));
+ CodePatcher::PatchStaticCallAt(caller_frame->pc(), target_code.EntryPoint());
+ caller_code.SetStaticCallTargetCodeAt(caller_frame->pc(), target_code);
if (FLAG_trace_patching) {
OS::Print("PatchStaticCall: patching from %#"Px" to '%s' %#"Px"\n",
caller_frame->pc(),
target_function.ToFullyQualifiedCString(),
- new_target);
+ target_code.EntryPoint());
}
+ arguments.SetReturn(target_code);
}
@@ -904,8 +869,7 @@
// Gets called from debug stub when code reaches a breakpoint.
-// Arg0: function object of the static function that was about to be called.
-DEFINE_RUNTIME_ENTRY(BreakpointStaticHandler, 1) {
+DEFINE_RUNTIME_ENTRY(BreakpointStaticHandler, 0) {
ASSERT(arguments.ArgCount() ==
kBreakpointStaticHandlerRuntimeEntry.argument_count());
ASSERT(isolate->debugger() != NULL);
@@ -913,13 +877,20 @@
// Make sure the static function that is about to be called is
// compiled. The stub will jump to the entry point without any
// further tests.
- const Function& function = Function::CheckedHandle(arguments.ArgAt(0));
+ DartFrameIterator iterator;
+ StackFrame* caller_frame = iterator.NextFrame();
+ ASSERT(caller_frame != NULL);
+ const Code& code = Code::Handle(caller_frame->LookupDartCode());
+ const Function& function =
+ Function::Handle(code.GetStaticCallTargetFunctionAt(caller_frame->pc()));
+
if (!function.HasCode()) {
const Error& error = Error::Handle(Compiler::CompileFunction(function));
if (!error.IsNull()) {
Exceptions::PropagateError(error);
}
}
+ arguments.SetReturn(Code::ZoneHandle(function.CurrentCode()));
}
@@ -1376,12 +1347,6 @@
const Array& function_args = Array::CheckedHandle(arguments.ArgAt(1));
const String& function_name = String::Handle(Symbols::Call());
GrowableArray<const Object*> dart_arguments(5);
- if (instance.IsNull()) {
- dart_arguments.Add(&function_name);
- dart_arguments.Add(&function_args);
- Exceptions::ThrowByType(Exceptions::kNullPointer, dart_arguments);
- UNREACHABLE();
- }
// TODO(regis): Resolve and invoke "call" method, if existing.
@@ -1565,13 +1530,10 @@
// The caller must be a static call in a Dart frame, or an entry frame.
-// Patch static call to point to 'new_entry_point'.
-DEFINE_RUNTIME_ENTRY(FixCallersTarget, 1) {
+// Patch static call to point to valid code's entry point.
+DEFINE_RUNTIME_ENTRY(FixCallersTarget, 0) {
ASSERT(arguments.ArgCount() ==
kFixCallersTargetRuntimeEntry.argument_count());
- const Function& function = Function::CheckedHandle(arguments.ArgAt(0));
- ASSERT(!function.IsNull());
- ASSERT(function.HasCode());
StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames);
StackFrame* frame = iterator.NextFrame();
@@ -1579,29 +1541,25 @@
frame = iterator.NextFrame();
}
ASSERT(frame != NULL);
- if (!frame->IsEntryFrame()) {
- ASSERT(frame->IsDartFrame());
- uword target = 0;
- Function& target_function = Function::Handle();
- CodePatcher::GetStaticCallAt(frame->pc(), &target_function, &target);
- ASSERT(target_function.HasCode());
- ASSERT(target_function.raw() == function.raw());
- const Code& target_code = Code::Handle(function.CurrentCode());
- const uword new_entry_point = target_code.EntryPoint();
- ASSERT(target != new_entry_point); // Why patch otherwise.
- CodePatcher::PatchStaticCallAt(frame->pc(), new_entry_point);
- const Code& code = Code::Handle(frame->LookupDartCode());
- bool found = UpdateResolvedStaticCall(code,
- frame->pc() - code.EntryPoint(),
- target_code);
- ASSERT(found);
- if (FLAG_trace_patching) {
- OS::Print("FixCallersTarget: patching from %#"Px" to '%s' %#"Px"\n",
- frame->pc(),
- target_function.ToFullyQualifiedCString(),
- new_entry_point);
- }
+ if (frame->IsEntryFrame()) {
+ // Since function's current code is always unpatched, the entry frame always
+ // calls to unpatched code.
+ UNREACHABLE();
}
+ ASSERT(frame->IsDartFrame());
+ const Code& caller_code = Code::Handle(frame->LookupDartCode());
+ const Function& target_function = Function::Handle(
+ caller_code.GetStaticCallTargetFunctionAt(frame->pc()));
+ const Code& target_code = Code::Handle(target_function.CurrentCode());
+ CodePatcher::PatchStaticCallAt(frame->pc(), target_code.EntryPoint());
+ caller_code.SetStaticCallTargetCodeAt(frame->pc(), target_code);
+ if (FLAG_trace_patching) {
+ OS::Print("FixCallersTarget: patching from %#"Px" to '%s' %#"Px"\n",
+ frame->pc(),
+ Function::Handle(target_code.function()).ToFullyQualifiedCString(),
+ target_code.EntryPoint());
+ }
+ arguments.SetReturn(target_code);
}
diff --git a/runtime/vm/code_patcher.h b/runtime/vm/code_patcher.h
index ebe8980..8377692 100644
--- a/runtime/vm/code_patcher.h
+++ b/runtime/vm/code_patcher.h
@@ -43,10 +43,7 @@
// or dynamic Dart call.
static bool IsDartCall(uword return_address);
- // Get static call information.
- static void GetStaticCallAt(uword return_address,
- Function* function,
- uword* target);
+ static uword GetStaticCallTargetAt(uword return_address);
// Get instance call information.
static void GetInstanceCallAt(uword return_address,
diff --git a/runtime/vm/code_patcher_arm.cc b/runtime/vm/code_patcher_arm.cc
index e67ce9d..0211183 100644
--- a/runtime/vm/code_patcher_arm.cc
+++ b/runtime/vm/code_patcher_arm.cc
@@ -10,7 +10,6 @@
namespace dart {
void CodePatcher::GetStaticCallAt(uword return_address,
- Function* function,
uword* target) {
UNIMPLEMENTED();
}
diff --git a/runtime/vm/code_patcher_ia32.cc b/runtime/vm/code_patcher_ia32.cc
index fc9a340..83260ce 100644
--- a/runtime/vm/code_patcher_ia32.cc
+++ b/runtime/vm/code_patcher_ia32.cc
@@ -14,7 +14,7 @@
namespace dart {
-// The pattern of a Dart call is:
+// The pattern of a Dart instance call is:
// 1: mov ECX, immediate 1
// 2: mov EDX, immediate 2
// 3: call target_address
@@ -97,27 +97,6 @@
};
-// The expected pattern of a dart static call:
-// mov ECX, function_object
-// mov EDX, argument_descriptor_array
-// call target_address
-// <- return address
-class StaticCall : public DartCallPattern {
- public:
- explicit StaticCall(uword return_address)
- : DartCallPattern(return_address) {}
-
- RawFunction* function() const {
- Function& f = Function::Handle();
- f ^= reinterpret_cast<RawObject*>(immediate_one());
- return f.raw();
- }
-
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(StaticCall);
-};
-
-
// The expected pattern of a dart instance call:
// mov ECX, ic-data
// mov EDX, argument_descriptor_array
@@ -139,14 +118,59 @@
};
-void CodePatcher::GetStaticCallAt(uword return_address,
- Function* function,
- uword* target) {
- ASSERT(function != NULL);
- ASSERT(target != NULL);
+// The expected pattern of a dart static call:
+// mov EDX, argument_descriptor_array
+// call target_address
+// <- return address
+class StaticCall : public ValueObject {
+ public:
+ explicit StaticCall(uword return_address)
+ : start_(return_address - (kNumInstructions * kInstructionSize)) {
+ ASSERT(IsValid(return_address));
+ ASSERT(kInstructionSize == Assembler::kCallExternalLabelSize);
+ }
+
+ static bool IsValid(uword return_address) {
+ uint8_t* code_bytes =
+ reinterpret_cast<uint8_t*>(
+ return_address - (kNumInstructions * kInstructionSize));
+ return (code_bytes[0] == 0xBA) &&
+ (code_bytes[1 * kInstructionSize] == 0xE8);
+ }
+
+ uword target() const {
+ const uword offset = *reinterpret_cast<uword*>(call_address() + 1);
+ return return_address() + offset;
+ }
+
+ void set_target(uword target) const {
+ uword* target_addr = reinterpret_cast<uword*>(call_address() + 1);
+ uword offset = target - return_address();
+ *target_addr = offset;
+ CPU::FlushICache(call_address(), kInstructionSize);
+ }
+
+ static const int kNumInstructions = 2;
+ static const int kInstructionSize = 5; // All instructions have same length.
+
+ private:
+ uword return_address() const {
+ return start_ + kNumInstructions * kInstructionSize;
+ }
+
+ uword call_address() const {
+ return start_ + 1 * kInstructionSize;
+ }
+
+ uword start_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(StaticCall);
+};
+
+
+uword CodePatcher::GetStaticCallTargetAt(uword return_address) {
StaticCall call(return_address);
- *target = call.target();
- *function = call.function();
+ return call.target();
}
diff --git a/runtime/vm/code_patcher_x64.cc b/runtime/vm/code_patcher_x64.cc
index 059c9cd..58a3785 100644
--- a/runtime/vm/code_patcher_x64.cc
+++ b/runtime/vm/code_patcher_x64.cc
@@ -14,7 +14,7 @@
namespace dart {
-// The pattern of a Dart call is:
+// The pattern of a Dart instance call is:
// 00: 48 bb imm64 mov RBX, immediate 1
// 10: 49 ba imm64 mov R10, immediate 2
// 20: 49 bb imm64 mov R11, target_address
@@ -87,24 +87,13 @@
};
-// A Dart static call passes the function object in RBX.
-class StaticCall : public DartCallPattern {
- public:
- explicit StaticCall(uword return_address)
- : DartCallPattern(return_address) {}
-
- RawFunction* function() const {
- Function& f = Function::Handle();
- f ^= reinterpret_cast<RawObject*>(immediate_one());
- return f.raw();
- }
-
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(StaticCall);
-};
-
-
// A Dart instance call passes the ic-data in RBX.
+// The expected pattern of a dart instance call:
+// mov RBX, ic-data
+// mov R10, argument_descriptor_array
+// mov R11, target_address
+// call R11
+// <- return address
class InstanceCall : public DartCallPattern {
public:
explicit InstanceCall(uword return_address)
@@ -121,14 +110,50 @@
};
-void CodePatcher::GetStaticCallAt(uword return_address,
- Function* function,
- uword* target) {
- ASSERT(function != NULL);
- ASSERT(target != NULL);
+// The expected pattern of a dart static call:
+// mov R10, argument_descriptor_array (10 bytes)
+// mov R11, target_address (10 bytes)
+// call R11 (3 bytes)
+// <- return address
+class StaticCall : public ValueObject {
+ public:
+ explicit StaticCall(uword return_address)
+ : start_(return_address - kCallPatternSize) {
+ ASSERT(IsValid(return_address));
+ ASSERT((kCallPatternSize - 10) == Assembler::kCallExternalLabelSize);
+ }
+
+ static const int kCallPatternSize = 23;
+
+ static bool IsValid(uword return_address) {
+ uint8_t* code_bytes =
+ reinterpret_cast<uint8_t*>(return_address - kCallPatternSize);
+ return (code_bytes[00] == 0x49) && (code_bytes[01] == 0xBA) &&
+ (code_bytes[10] == 0x49) && (code_bytes[11] == 0xBB) &&
+ (code_bytes[20] == 0x41) && (code_bytes[21] == 0xFF) &&
+ (code_bytes[22] == 0xD3);
+ }
+
+ uword target() const {
+ return *reinterpret_cast<uword*>(start_ + 10 + 2);
+ }
+
+ void set_target(uword target) const {
+ uword* target_addr = reinterpret_cast<uword*>(start_ + 10 + 2);
+ *target_addr = target;
+ CPU::FlushICache(start_ + 10, 2 + 8);
+ }
+
+ private:
+ uword start_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(StaticCall);
+};
+
+
+uword CodePatcher::GetStaticCallTargetAt(uword return_address) {
StaticCall call(return_address);
- *target = call.target();
- *function = call.function();
+ return call.target();
}
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 4b11672..25cb8a3 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -277,6 +277,7 @@
graph_compiler.FinalizeVarDescriptors(code);
graph_compiler.FinalizeExceptionHandlers(code);
graph_compiler.FinalizeComments(code);
+ graph_compiler.FinalizeStaticCallTargetsTable(code);
if (optimized) {
CodePatcher::PatchEntry(Code::Handle(function.CurrentCode()));
function.SetCode(code);
@@ -416,6 +417,25 @@
const ExceptionHandlers& handlers =
ExceptionHandlers::Handle(code.exception_handlers());
OS::Print("%s}\n", handlers.ToCString());
+
+ {
+ OS::Print("Static call target functions {\n");
+ const Array& table = Array::Handle(code.static_calls_target_table());
+ Smi& offset = Smi::Handle();
+ Function& function = Function::Handle();
+ Code& code = Code::Handle();
+ for (intptr_t i = 0; i < table.Length();
+ i += Code::kSCallTableEntryLength) {
+ offset ^= table.At(i + Code::kSCallTableOffsetEntry);
+ function ^= table.At(i + Code::kSCallTableFunctionEntry);
+ code ^= table.At(i + Code::kSCallTableCodeEntry);
+ OS::Print(" 0x%"Px": %s, %p\n",
+ start + offset.Value(),
+ function.ToFullyQualifiedCString(),
+ code.raw());
+ }
+ OS::Print("}\n");
+ }
}
diff --git a/runtime/vm/constants_ia32.h b/runtime/vm/constants_ia32.h
index 1c8325f..02a84b7 100644
--- a/runtime/vm/constants_ia32.h
+++ b/runtime/vm/constants_ia32.h
@@ -69,7 +69,8 @@
TIMES_1 = 0,
TIMES_2 = 1,
TIMES_4 = 2,
- TIMES_8 = 3
+ TIMES_8 = 3,
+ TIMES_HALF_WORD_SIZE = kWordSizeLog2 - 1
};
diff --git a/runtime/vm/constants_x64.h b/runtime/vm/constants_x64.h
index 579ea56..38a2046 100644
--- a/runtime/vm/constants_x64.h
+++ b/runtime/vm/constants_x64.h
@@ -51,7 +51,15 @@
XMM5 = 5,
XMM6 = 6,
XMM7 = 7,
- kNumberOfXmmRegisters = 8,
+ XMM8 = 8,
+ XMM9 = 9,
+ XMM10 = 10,
+ XMM11 = 11,
+ XMM12 = 12,
+ XMM13 = 13,
+ XMM14 = 14,
+ XMM15 = 15,
+ kNumberOfXmmRegisters = 16,
kNoXmmRegister = -1 // Signals an illegal register.
};
@@ -84,7 +92,8 @@
TIMES_1 = 0,
TIMES_2 = 1,
TIMES_4 = 2,
- TIMES_8 = 3
+ TIMES_8 = 3,
+ TIMES_HALF_WORD_SIZE = kWordSizeLog2 - 1
};
diff --git a/runtime/vm/custom_isolate_test.cc b/runtime/vm/custom_isolate_test.cc
index 2090a7d..d8e2444 100644
--- a/runtime/vm/custom_isolate_test.cc
+++ b/runtime/vm/custom_isolate_test.cc
@@ -24,7 +24,7 @@
static const char* kCustomIsolateScriptChars =
- "#import('dart:isolate');\n"
+ "import 'dart:isolate';\n"
"\n"
"ReceivePort mainPort;\n"
"\n"
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 99e2886..fcc3501 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -48,12 +48,12 @@
// TODO(turnidge): We should add a corresponding Dart::Cleanup.
-bool Dart::InitOnce(Dart_IsolateCreateCallback create,
+const char* Dart::InitOnce(Dart_IsolateCreateCallback create,
Dart_IsolateInterruptCallback interrupt,
Dart_IsolateShutdownCallback shutdown) {
// TODO(iposva): Fix race condition here.
if (vm_isolate_ != NULL || !Flags::Initialized()) {
- return false;
+ return "VM already initialized.";
}
OS::InitOnce();
VirtualMemory::InitOnce();
@@ -78,8 +78,10 @@
Symbols::InitOnce(vm_isolate_);
CPUFeatures::InitOnce();
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
- // Dart VM requires at least SSE3.
- if (!CPUFeatures::sse3_supported()) return false;
+ // Dart VM requires at least SSE2.
+ if (!CPUFeatures::sse2_supported()) {
+ return "SSE2 is required.";
+ }
#endif
PremarkingVisitor premarker(vm_isolate_);
vm_isolate_->heap()->IterateOldObjects(&premarker);
@@ -89,7 +91,7 @@
Isolate::SetCreateCallback(create);
Isolate::SetInterruptCallback(interrupt);
Isolate::SetShutdownCallback(shutdown);
- return true;
+ return NULL;
}
diff --git a/runtime/vm/dart.h b/runtime/vm/dart.h
index 4b741e0..585cddd 100644
--- a/runtime/vm/dart.h
+++ b/runtime/vm/dart.h
@@ -18,9 +18,9 @@
class Dart : public AllStatic {
public:
- static bool InitOnce(Dart_IsolateCreateCallback create,
- Dart_IsolateInterruptCallback interrupt,
- Dart_IsolateShutdownCallback shutdown);
+ static const char* InitOnce(Dart_IsolateCreateCallback create,
+ Dart_IsolateInterruptCallback interrupt,
+ Dart_IsolateShutdownCallback shutdown);
static Isolate* CreateIsolate(const char* name_prefix);
static RawError* InitializeIsolate(const uint8_t* snapshot, void* data);
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 88d0389..aed8a10 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -739,7 +739,12 @@
DART_EXPORT bool Dart_Initialize(Dart_IsolateCreateCallback create,
Dart_IsolateInterruptCallback interrupt,
Dart_IsolateShutdownCallback shutdown) {
- return Dart::InitOnce(create, interrupt, shutdown);
+ const char* err_msg = Dart::InitOnce(create, interrupt, shutdown);
+ if (err_msg != NULL) {
+ OS::PrintErr("Dart_Initialize: %s\n", err_msg);
+ return false;
+ }
+ return true;
}
DART_EXPORT bool Dart_SetVMFlags(int argc, const char** argv) {
@@ -1571,7 +1576,7 @@
}
-DART_EXPORT Dart_Handle Dart_NewStringFromUTF32(const uint32_t* utf32_array,
+DART_EXPORT Dart_Handle Dart_NewStringFromUTF32(const int32_t* utf32_array,
intptr_t length) {
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 0fa7e0b..ecc1df1 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -541,7 +541,7 @@
EXPECT(Dart_IsString(ext16));
EXPECT(Dart_IsExternalString(ext16));
- uint32_t data32[] = { 'f', 'o', 'u', 'r', 0x10FFFF };
+ int32_t data32[] = { 'f', 'o', 'u', 'r', 0x10FFFF };
Dart_Handle str32 = Dart_NewStringFromUTF32(data32, ARRAY_SIZE(data32));
EXPECT_VALID(str32);
@@ -2647,7 +2647,7 @@
" return new Fields();\n"
"}\n";
const char* kImportedScriptChars =
- "#library('library_name');\n"
+ "library library_name;\n"
"var imported_fld = 'imported';\n"
"var _imported_fld = 'hidden imported';\n"
"get imported_getset_fld { return _gs_fld1; }\n"
@@ -2951,7 +2951,7 @@
TEST_CASE(InjectNativeFields3) {
const char* kScriptChars =
- "#import('dart:nativewrappers');"
+ "import 'dart:nativewrappers';"
"class NativeFields extends NativeFieldWrapperClass2 {\n"
" NativeFields(int i, int j) : fld1 = i, fld2 = j {}\n"
" int fld1;\n"
@@ -2993,7 +2993,7 @@
TEST_CASE(InjectNativeFields4) {
const char* kScriptChars =
- "#import('dart:nativewrappers');"
+ "import 'dart:nativewrappers';"
"class NativeFields extends NativeFieldWrapperClass2 {\n"
" NativeFields(int i, int j) : fld1 = i, fld2 = j {}\n"
" int fld1;\n"
@@ -3015,7 +3015,7 @@
// We expect the test script to fail finalization with the error below:
EXPECT(Dart_IsError(result));
Dart_Handle expected_error = Dart_Error(
- "'dart:test-lib': Error: line 1 pos 38: "
+ "'dart:test-lib': Error: line 1 pos 36: "
"class 'NativeFields' is trying to extend a native fields class, "
"but library '%s' has no native resolvers",
TestCase::url());
@@ -3025,7 +3025,7 @@
TEST_CASE(InjectNativeFieldsSuperClass) {
const char* kScriptChars =
- "#import('dart:nativewrappers');"
+ "import 'dart:nativewrappers';"
"class NativeFieldsSuper extends NativeFieldWrapperClass1 {\n"
" NativeFieldsSuper() : fld1 = 42 {}\n"
" int fld1;\n"
@@ -3185,7 +3185,7 @@
TEST_CASE(ImplicitNativeFieldAccess) {
const char* kScriptChars =
- "#import('dart:nativewrappers');"
+ "import 'dart:nativewrappers';"
"class NativeFields extends NativeFieldWrapperClass4 {\n"
" NativeFields(int i, int j) : fld1 = i, fld2 = j {}\n"
" int fld0;\n"
@@ -3811,11 +3811,11 @@
TEST_CASE(Invoke_CrossLibrary) {
const char* kLibrary1Chars =
- "#library('library1_name');\n"
+ "library library1_name;\n"
"void local() {}\n"
"void _local() {}\n";
const char* kLibrary2Chars =
- "#library('library2_name');\n"
+ "library library2_name;\n"
"void imported() {}\n"
"void _imported() {}\n";
@@ -5115,11 +5115,11 @@
TEST_CASE(LookupLibrary) {
const char* kScriptChars =
- "#import('library1.dart');"
+ "import 'library1_dart';"
"main() {}";
const char* kLibrary1Chars =
- "#library('library1.dart');"
- "#import('library2.dart');";
+ "library library1_dart;"
+ "import 'library2_dart';";
// Create a test library and Load up a test script in it.
Dart_Handle url = NewString(TestCase::url());
@@ -5129,7 +5129,7 @@
result = Dart_LoadScript(url, source);
EXPECT_VALID(result);
- url = NewString("library1.dart");
+ url = NewString("library1_dart");
source = NewString(kLibrary1Chars);
result = Dart_LoadLibrary(url, source);
EXPECT_VALID(result);
@@ -5162,7 +5162,7 @@
TEST_CASE(LibraryName) {
const char* kLibrary1Chars =
- "#library('library1_name');";
+ "library library1_name;";
Dart_Handle url = NewString("library1_url");
Dart_Handle source = NewString(kLibrary1Chars);
Dart_Handle lib = Dart_LoadLibrary(url, source);
@@ -5195,7 +5195,7 @@
TEST_CASE(LibraryUrl) {
const char* kLibrary1Chars =
- "#library('library1_name');";
+ "library library1_name;";
Dart_Handle url = NewString("library1_url");
Dart_Handle source = NewString(kLibrary1Chars);
Dart_Handle lib = Dart_LoadLibrary(url, source);
@@ -5228,7 +5228,7 @@
TEST_CASE(LibraryGetClassNames) {
const char* kLibraryChars =
- "#library('library_name');\n"
+ "library library_name;\n"
"\n"
"class A {}\n"
"class B {}\n"
@@ -5265,7 +5265,7 @@
TEST_CASE(GetFunctionNames) {
const char* kLibraryChars =
- "#library('library_name');\n"
+ "library library_name;\n"
"\n"
"void A() {}\n"
"get B => 11;\n"
@@ -5335,7 +5335,7 @@
TEST_CASE(GetVariableNames) {
const char* kLibraryChars =
- "#library('library_name');\n"
+ "library library_name;\n"
"\n"
"var A;\n"
"get B => 12;\n"
@@ -5400,9 +5400,9 @@
TEST_CASE(LibraryImportLibrary) {
const char* kLibrary1Chars =
- "#library('library1_name');";
+ "library library1_name;";
const char* kLibrary2Chars =
- "#library('library2_name');";
+ "library library2_name;";
Dart_Handle error = Dart_Error("incoming error");
Dart_Handle result;
@@ -5455,7 +5455,7 @@
TEST_CASE(ImportLibraryWithPrefix) {
const char* kLibrary1Chars =
- "#library('library1_name');"
+ "library library1_name;"
"int bar() => 42;";
Dart_Handle url1 = NewString("library1_url");
Dart_Handle source1 = NewString(kLibrary1Chars);
@@ -5464,7 +5464,7 @@
EXPECT(Dart_IsLibrary(lib1));
const char* kLibrary2Chars =
- "#library('library2_name');"
+ "library library2_name;"
"int foobar() => foo.bar();";
Dart_Handle url2 = NewString("library2_url");
Dart_Handle source2 = NewString(kLibrary2Chars);
@@ -5496,7 +5496,7 @@
TEST_CASE(LoadLibrary) {
const char* kLibrary1Chars =
- "#library('library1_name');";
+ "library library1_name;";
Dart_Handle error = Dart_Error("incoming error");
Dart_Handle result;
@@ -5548,7 +5548,7 @@
TEST_CASE(LoadLibrary_CompileError) {
const char* kLibrary1Chars =
- "#library('library1_name');"
+ "library library1_name;"
")";
Dart_Handle url = NewString("library1_url");
Dart_Handle source = NewString(kLibrary1Chars);
@@ -5560,7 +5560,7 @@
TEST_CASE(LoadSource) {
const char* kLibrary1Chars =
- "#library('library1_name');";
+ "library library1_name;";
const char* kSourceChars =
"// Something innocuous";
const char* kBadSourceChars =
@@ -5643,7 +5643,7 @@
TEST_CASE(LoadSource_LateLoad) {
const char* kLibrary1Chars =
- "#library('library1_name');\n"
+ "library library1_name;\n"
"class OldClass {\n"
" foo() => 'foo';\n"
"}\n";
@@ -5688,7 +5688,7 @@
TEST_CASE(LoadPatch) {
const char* kLibrary1Chars =
- "#library('library1_name');";
+ "library library1_name;";
const char* kSourceChars =
"external int foo();";
const char* kPatchChars =
@@ -5737,7 +5737,7 @@
TEST_CASE(ParsePatchLibrary) {
const char* kLibraryChars =
- "#library('patched_library');\n"
+ "library patched_library;\n"
"class A {\n"
" final fvalue;\n"
" var _f;\n"
@@ -5779,7 +5779,7 @@
"patch(x) => x*3;\n";
const char* kScriptChars =
- "#import('theLibrary');\n"
+ "import 'theLibrary';\n"
"e1() => unpatched();\n"
"m1() => topLevel(2);\n"
"m2() {\n"
@@ -5982,16 +5982,16 @@
// in the importing library.
TEST_CASE(ImportLibrary2) {
const char* kScriptChars =
- "#import('library1.dart');\n"
+ "import 'library1_dart';\n"
"var foo;\n"
"main() { foo = 0; }\n";
const char* kLibrary1Chars =
- "#library('library1.dart');\n"
- "#import('library2.dart');\n"
+ "library library1_dart;\n"
+ "import 'library2_dart';\n"
"var foo;\n";
const char* kLibrary2Chars =
- "#library('library2.dart');\n"
- "#import('library1.dart');\n"
+ "library library2_dart;\n"
+ "import 'library1_dart';\n"
"var foo;\n";
Dart_Handle result;
// Create a test library and Load up a test script in it.
@@ -6001,11 +6001,11 @@
EXPECT_VALID(result);
result = Dart_LoadScript(url, source);
- url = NewString("library1.dart");
+ url = NewString("library1_dart");
source = NewString(kLibrary1Chars);
Dart_LoadLibrary(url, source);
- url = NewString("library2.dart");
+ url = NewString("library2_dart");
source = NewString(kLibrary2Chars);
Dart_LoadLibrary(url, source);
@@ -6018,15 +6018,15 @@
// an error if that name is referenced.
TEST_CASE(ImportLibrary3) {
const char* kScriptChars =
- "#import('library2.dart');\n"
- "#import('library1.dart');\n"
+ "import 'library2_dart';\n"
+ "import 'library1_dart';\n"
"var foo_top = 10; // foo has dup def. So should be an error.\n"
"main() { foo = 0; }\n";
const char* kLibrary1Chars =
- "#library('library1.dart');\n"
+ "library library1_dart;\n"
"var foo;";
const char* kLibrary2Chars =
- "#library('library2.dart');\n"
+ "library library2_dart;\n"
"var foo;";
Dart_Handle result;
@@ -6038,11 +6038,11 @@
result = Dart_LoadScript(url, source);
EXPECT_VALID(result);
- url = NewString("library2.dart");
+ url = NewString("library2_dart");
source = NewString(kLibrary2Chars);
Dart_LoadLibrary(url, source);
- url = NewString("library1.dart");
+ url = NewString("library1_dart");
source = NewString(kLibrary1Chars);
Dart_LoadLibrary(url, source);
@@ -6056,14 +6056,14 @@
// not an error if that name is not used.
TEST_CASE(ImportLibrary4) {
const char* kScriptChars =
- "#import('library2.dart');\n"
- "#import('library1.dart');\n"
+ "import 'library2_dart';\n"
+ "import 'library1_dart';\n"
"main() { }\n";
const char* kLibrary1Chars =
- "#library('library1.dart');\n"
+ "library library1_dart;\n"
"var foo;";
const char* kLibrary2Chars =
- "#library('library2.dart');\n"
+ "library library2_dart;\n"
"var foo;";
Dart_Handle result;
@@ -6075,11 +6075,11 @@
result = Dart_LoadScript(url, source);
EXPECT_VALID(result);
- url = NewString("library2.dart");
+ url = NewString("library2_dart");
source = NewString(kLibrary2Chars);
Dart_LoadLibrary(url, source);
- url = NewString("library1.dart");
+ url = NewString("library1_dart");
source = NewString(kLibrary1Chars);
Dart_LoadLibrary(url, source);
@@ -6090,13 +6090,13 @@
TEST_CASE(ImportLibrary5) {
const char* kScriptChars =
- "#import('lib.dart');\n"
+ "import 'lib.dart';\n"
"interface Y {\n"
" void set handler(void callback(List<int> x));\n"
"}\n"
"void main() {}\n";
const char* kLibraryChars =
- "#library('lib.dart');\n"
+ "library lib.dart;\n"
"interface X {\n"
" void set handler(void callback(List<int> x));\n"
"}\n";
@@ -6161,7 +6161,7 @@
TestIsolateScope __test_isolate__;
const char* kScriptChars =
- "#import('dart:isolate');\n"
+ "import 'dart:isolate';\n"
"void callPort(SendPort port) {\n"
" port.call(null).then((message) {\n"
" throw new Exception(message);\n"
@@ -6212,8 +6212,8 @@
void* data,
char** error) {
const char* kScriptChars =
- "#import('builtin');\n"
- "#import('dart:isolate');\n"
+ "import 'builtin';\n"
+ "import 'dart:isolate';\n"
"void entry() {\n"
" port.receive((message, replyTo) {\n"
" if (message) {\n"
@@ -6770,7 +6770,7 @@
TEST_CASE(RangeLimits) {
uint8_t chars8[1] = {'a'};
uint16_t chars16[1] = {'a'};
- uint32_t chars32[1] = {'a'};
+ int32_t chars32[1] = {'a'};
EXPECT_ERROR(Dart_NewList(-1),
"expects argument 'length' to be in the range");
diff --git a/runtime/vm/dart_api_message.cc b/runtime/vm/dart_api_message.cc
index 64eea31..4cee392 100644
--- a/runtime/vm/dart_api_message.cc
+++ b/runtime/vm/dart_api_message.cc
@@ -17,7 +17,8 @@
ReAlloc alloc)
: BaseReader(buffer, length),
alloc_(alloc),
- backward_references_(kNumInitialReferences) {
+ backward_references_(kNumInitialReferences),
+ vm_symbol_references_(NULL) {
Init();
}
@@ -215,13 +216,29 @@
Dart_CObject* ApiMessageReader::ReadVMSymbol(intptr_t object_id) {
if (Symbols::IsVMSymbolId(object_id)) {
+ intptr_t symbol_id = object_id - kMaxPredefinedObjectIds;
+ Dart_CObject* object;
+ if (vm_symbol_references_ != NULL &&
+ (object = vm_symbol_references_[symbol_id]) != NULL) {
+ return object;
+ }
+
+ if (vm_symbol_references_ == NULL) {
+ intptr_t size = sizeof(*vm_symbol_references_) * Symbols::kMaxId;
+ vm_symbol_references_ =
+ reinterpret_cast<Dart_CObject**>(alloc_(NULL, 0, size));
+ memset(vm_symbol_references_, 0, size);
+ }
+
RawOneByteString* str =
reinterpret_cast<RawOneByteString*>(Symbols::GetVMSymbol(object_id));
intptr_t len = Smi::Value(str->ptr()->length_);
- Dart_CObject* object = AllocateDartCObjectString(len);
+ object = AllocateDartCObjectString(len);
char* p = object->value.as_string;
memmove(p, str->ptr()->data_, len);
p[len] = '\0';
+ ASSERT(vm_symbol_references_[symbol_id] == NULL);
+ vm_symbol_references_[symbol_id] = object;
return object;
}
// No other VM isolate objects are supported.
diff --git a/runtime/vm/dart_api_message.h b/runtime/vm/dart_api_message.h
index c37d8fb..dbd7278 100644
--- a/runtime/vm/dart_api_message.h
+++ b/runtime/vm/dart_api_message.h
@@ -109,6 +109,7 @@
// function.
ReAlloc alloc_;
ApiGrowableArray<BackRefNode*> backward_references_;
+ Dart_CObject** vm_symbol_references_;
Dart_CObject type_arguments_marker;
Dart_CObject dynamic_type_marker;
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 96019a9..5d5cf71 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -575,8 +575,7 @@
break;
}
case PcDescriptors::kFuncCall: {
- Function& func = Function::Handle();
- CodePatcher::GetStaticCallAt(pc_, &func, &saved_bytes_.target_address_);
+ saved_bytes_.target_address_ = CodePatcher::GetStaticCallTargetAt(pc_);
CodePatcher::PatchStaticCallAt(pc_,
StubCode::BreakpointStaticEntryPoint());
break;
@@ -1403,9 +1402,10 @@
}
} else if (bpt->breakpoint_kind_ == PcDescriptors::kFuncCall) {
func_to_instrument = bpt->function();
- Function& callee = Function::Handle();
- uword target;
- CodePatcher::GetStaticCallAt(bpt->pc_, &callee, &target);
+ const Code& code = Code::Handle(func_to_instrument.CurrentCode());
+ const Function& callee =
+ Function::Handle(code.GetStaticCallTargetFunctionAt(bpt->pc_));
+ ASSERT(!callee.IsNull());
if (IsDebuggable(callee)) {
func_to_instrument = callee.raw();
}
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index fc2e2c9..479ad64 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -144,7 +144,7 @@
Instance& exception = Instance::Handle(incoming_exception.raw());
if (exception.IsNull()) {
GrowableArray<const Object*> arguments;
- exception ^= Exceptions::Create(Exceptions::kNullPointer, arguments);
+ exception ^= Exceptions::Create(Exceptions::kNullThrown, arguments);
}
uword handler_pc = 0;
uword handler_sp = 0;
@@ -427,18 +427,14 @@
library = Library::CoreLibrary();
class_name = Symbols::New("InternalError");
break;
- case kNullPointer:
+ case kNullThrown:
library = Library::CoreLibrary();
- class_name = Symbols::New("NullPointerException");
+ class_name = Symbols::New("NullThrownError");
break;
case kIllegalJSRegExp:
library = Library::CoreLibrary();
class_name = Symbols::New("IllegalJSRegExpException");
break;
- case kArgumentError:
- library = Library::CoreLibrary();
- class_name = Symbols::New("ArgumentError");
- break;
case kIsolateSpawn:
library = Library::IsolateLibrary();
class_name = Symbols::New("IsolateSpawnException");
diff --git a/runtime/vm/exceptions.h b/runtime/vm/exceptions.h
index 1fe2665..0cc048f 100644
--- a/runtime/vm/exceptions.h
+++ b/runtime/vm/exceptions.h
@@ -56,9 +56,8 @@
kStackOverflow,
kOutOfMemory,
kInternalError,
- kNullPointer,
+ kNullThrown,
kIllegalJSRegExp,
- kArgumentError,
kIsolateSpawn
};
diff --git a/runtime/vm/flow_graph_allocator.cc b/runtime/vm/flow_graph_allocator.cc
index 609d1d6..939f393 100644
--- a/runtime/vm/flow_graph_allocator.cc
+++ b/runtime/vm/flow_graph_allocator.cc
@@ -62,6 +62,7 @@
FlowGraphAllocator::FlowGraphAllocator(const FlowGraph& flow_graph)
: flow_graph_(flow_graph),
+ reaching_defs_(flow_graph),
mint_values_(NULL),
block_order_(flow_graph.reverse_postorder()),
postorder_(flow_graph.postorder()),
@@ -146,9 +147,15 @@
}
// Handle uses.
+ LocationSummary* locs = current->locs();
+ ASSERT(locs->input_count() == current->InputCount());
for (intptr_t j = 0; j < current->InputCount(); j++) {
Value* input = current->InputAt(j);
const intptr_t use = input->definition()->ssa_temp_index();
+
+ ASSERT(!locs->in(j).IsConstant() || input->BindsToConstant());
+ if (locs->in(j).IsConstant()) continue;
+
live_in->Add(use);
}
@@ -182,6 +189,8 @@
// live-in for a predecessor.
for (intptr_t k = 0; k < phi->InputCount(); k++) {
Value* val = phi->InputAt(k);
+ if (val->BindsToConstant()) continue;
+
BlockEntryInstr* pred = block->PredecessorAt(k);
const intptr_t use = val->definition()->ssa_temp_index();
if (!kill_[pred->postorder_number()]->Contains(use)) {
@@ -517,9 +526,12 @@
void FlowGraphAllocator::BuildLiveRanges() {
const intptr_t block_count = postorder_.length();
ASSERT(postorder_.Last()->IsGraphEntry());
+ BitVector* current_interference_set = NULL;
for (intptr_t i = 0; i < (block_count - 1); i++) {
BlockEntryInstr* block = postorder_[i];
+ BlockInfo* block_info = BlockInfoAt(block->start_pos());
+
// For every SSA value that is live out of this block, create an interval
// that covers the whole block. It will be shortened if we encounter a
// definition of this value in this block.
@@ -528,23 +540,33 @@
range->AddUseInterval(block->start_pos(), block->end_pos());
}
+ BlockInfo* loop_header = block_info->loop_header();
+ if ((loop_header != NULL) && (loop_header->last_block() == block)) {
+ current_interference_set =
+ new BitVector(flow_graph_.max_virtual_register_number());
+ ASSERT(loop_header->backedge_interference() == NULL);
+ loop_header->set_backedge_interference(
+ current_interference_set);
+ }
+
// Connect outgoing phi-moves that were created in NumberInstructions
// and find last instruction that contributes to liveness.
- Instruction* current = ConnectOutgoingPhiMoves(block);
+ Instruction* current = ConnectOutgoingPhiMoves(block,
+ current_interference_set);
// Now process all instructions in reverse order.
while (current != block) {
// Skip parallel moves that we insert while processing instructions.
if (!current->IsParallelMove()) {
- ProcessOneInstruction(block, current);
+ ProcessOneInstruction(block, current, current_interference_set);
}
current = current->previous();
}
// Check if any values live into the loop can be spilled for free.
- BlockInfo* block_info = BlockInfoAt(block->start_pos());
if (block_info->is_loop_header()) {
+ current_interference_set = NULL;
for (BitVector::Iterator it(live_in_[i]); !it.Done(); it.Advance()) {
LiveRange* range = GetLiveRange(it.Current());
if (HasOnlyUnconstrainedUsesInLoop(range, block_info)) {
@@ -650,7 +672,7 @@
//
Instruction* FlowGraphAllocator::ConnectOutgoingPhiMoves(
- BlockEntryInstr* block) {
+ BlockEntryInstr* block, BitVector* interfere_at_backedge) {
Instruction* last = block->last_instruction();
GotoInstr* goto_instr = last->AsGoto();
@@ -696,7 +718,9 @@
// value --*
//
- LiveRange* range = GetLiveRange(val->definition()->ssa_temp_index());
+ const intptr_t vreg = val->definition()->ssa_temp_index();
+ LiveRange* range = GetLiveRange(vreg);
+ if (interfere_at_backedge != NULL) interfere_at_backedge->Add(vreg);
range->AddUseInterval(block->start_pos(), pos);
range->AddHintedUse(pos, move->src_slot(), move->dest_slot());
@@ -821,7 +845,8 @@
// Create and update live ranges corresponding to instruction's inputs,
// temporaries and output.
void FlowGraphAllocator::ProcessOneInstruction(BlockEntryInstr* block,
- Instruction* current) {
+ Instruction* current,
+ BitVector* interference_set) {
LocationSummary* locs = current->locs();
Definition* def = current->AsDefinition();
@@ -1065,6 +1090,12 @@
range->AddHintedUse(pos, out, move->src_slot());
range->AddUse(pos, move->dest_slot());
range->AddUse(pos, locs->in_slot(0));
+
+ if ((interference_set != NULL) &&
+ (range->vreg() >= 0) &&
+ interference_set->Contains(range->vreg())) {
+ interference_set->Add(input->ssa_temp_index());
+ }
} else {
// Normal unallocated location that requires a register. Expected shape of
// live range:
@@ -1451,7 +1482,7 @@
LiveRange* FlowGraphAllocator::SplitBetween(LiveRange* range,
intptr_t from,
intptr_t to) {
- TRACE_ALLOC(OS::Print("split %"Pd" [%"Pd", %"Pd") between [%"Pd", %"Pd")\n",
+ TRACE_ALLOC(OS::Print("split v%"Pd" [%"Pd", %"Pd") between [%"Pd", %"Pd")\n",
range->vreg(), range->Start(), range->End(), from, to));
intptr_t split_pos = kIllegalPosition;
@@ -1489,7 +1520,7 @@
intptr_t from,
intptr_t to) {
ASSERT(from < to);
- TRACE_ALLOC(OS::Print("spill %"Pd" [%"Pd", %"Pd") "
+ TRACE_ALLOC(OS::Print("spill v%"Pd" [%"Pd", %"Pd") "
"between [%"Pd", %"Pd")\n",
range->vreg(), range->Start(), range->End(), from, to));
LiveRange* tail = range->SplitAt(from);
@@ -1507,7 +1538,7 @@
void FlowGraphAllocator::SpillAfter(LiveRange* range, intptr_t from) {
- TRACE_ALLOC(OS::Print("spill %"Pd" [%"Pd", %"Pd") after %"Pd"\n",
+ TRACE_ALLOC(OS::Print("spill v%"Pd" [%"Pd", %"Pd") after %"Pd"\n",
range->vreg(), range->Start(), range->End(), from));
// When spilling the value inside the loop check if this spill can
@@ -1614,6 +1645,72 @@
}
+void ReachingDefs::AddPhi(PhiInstr* phi) {
+ if (phi->reaching_defs() == NULL) {
+ phi->set_reaching_defs(
+ new BitVector(flow_graph_.max_virtual_register_number()));
+
+ // Compute initial set reaching defs set.
+ bool depends_on_phi = false;
+ for (intptr_t i = 0; i < phi->InputCount(); i++) {
+ Definition* input = phi->InputAt(i)->definition();
+ if (input->IsPhi()) {
+ depends_on_phi = true;
+ }
+ phi->reaching_defs()->Add(input->ssa_temp_index());
+ }
+
+ // If this phi depends on another phi then we need fix point iteration.
+ if (depends_on_phi) phis_.Add(phi);
+ }
+}
+
+
+void ReachingDefs::Compute() {
+ // Transitively collect all phis that are used by the given phi.
+ for (intptr_t i = 0; i < phis_.length(); i++) {
+ PhiInstr* phi = phis_[i];
+
+ // Add all phis that affect this phi to the list.
+ for (intptr_t i = 0; i < phi->InputCount(); i++) {
+ PhiInstr* input_phi = phi->InputAt(i)->definition()->AsPhi();
+ if (input_phi != NULL) {
+ AddPhi(input_phi);
+ }
+ }
+ }
+
+ // Propagate values until fix point is reached.
+ bool changed;
+ do {
+ changed = false;
+ for (intptr_t i = 0; i < phis_.length(); i++) {
+ PhiInstr* phi = phis_[i];
+ for (intptr_t i = 0; i < phi->InputCount(); i++) {
+ PhiInstr* input_phi = phi->InputAt(i)->definition()->AsPhi();
+ if (input_phi != NULL) {
+ if (phi->reaching_defs()->AddAll(input_phi->reaching_defs())) {
+ changed = true;
+ }
+ }
+ }
+ }
+ } while (changed);
+
+ phis_.Clear();
+}
+
+
+BitVector* ReachingDefs::Get(PhiInstr* phi) {
+ if (phi->reaching_defs() == NULL) {
+ ASSERT(phis_.is_empty());
+ AddPhi(phi);
+ Compute();
+ }
+ return phi->reaching_defs();
+}
+
+
bool FlowGraphAllocator::AllocateFreeRegister(LiveRange* unallocated) {
intptr_t candidate = kNoRegister;
intptr_t free_until = 0;
@@ -1628,10 +1725,10 @@
candidate = hint.register_code();
}
- TRACE_ALLOC(OS::Print("found hint "));
- TRACE_ALLOC(hint.Print());
- TRACE_ALLOC(OS::Print(" for %"Pd": free until %"Pd"\n",
- unallocated->vreg(), free_until));
+ TRACE_ALLOC(OS::Print("found hint %s for v%"Pd": free until %"Pd"\n",
+ hint.Name(),
+ unallocated->vreg(),
+ free_until));
} else if (free_until != kMaxPosition) {
for (intptr_t reg = 0; reg < NumberOfRegisters(); ++reg) {
if (!blocked_registers_[reg] && (registers_[reg].length() == 0)) {
@@ -1642,6 +1739,66 @@
}
}
+ // We have a very good candidate (either hinted to us or completely free).
+ // If we are in a loop try to reduce number of moves on the back edge by
+ // searching for a candidate that does not interfere with phis on the back
+ // edge.
+ BlockInfo* loop_header = BlockInfoAt(unallocated->Start())->loop_header();
+ if ((unallocated->vreg() >= 0) &&
+ (loop_header != NULL) &&
+ (free_until >= loop_header->last_block()->end_pos()) &&
+ loop_header->backedge_interference()->Contains(unallocated->vreg())) {
+ ASSERT(static_cast<intptr_t>(kNumberOfXmmRegisters) <=
+ kNumberOfCpuRegisters);
+ bool used_on_backedge[kNumberOfCpuRegisters] = { false };
+
+ for (PhiIterator it(loop_header->entry()->AsJoinEntry());
+ !it.Done();
+ it.Advance()) {
+ PhiInstr* phi = it.Current();
+ if (phi->is_alive()) {
+ const intptr_t phi_vreg = phi->ssa_temp_index();
+ LiveRange* range = GetLiveRange(phi_vreg);
+ if (range->assigned_location().kind() == register_kind_) {
+ const intptr_t reg = range->assigned_location().register_code();
+
+ if (!reaching_defs_.Get(phi)->Contains(unallocated->vreg())) {
+ used_on_backedge[reg] = true;
+ }
+ }
+ }
+ }
+
+ if (used_on_backedge[candidate]) {
+ TRACE_ALLOC(OS::Print(
+ "considering %s for v%"Pd": has interference on the back edge"
+ " {loop [%"Pd", %"Pd")}\n",
+ MakeRegisterLocation(candidate, Location::kDouble).Name(),
+ unallocated->vreg(),
+ loop_header->entry()->start_pos(),
+ loop_header->last_block()->end_pos()));
+ for (intptr_t reg = 0; reg < NumberOfRegisters(); ++reg) {
+ if (blocked_registers_[reg] ||
+ (reg == candidate) ||
+ used_on_backedge[reg]) {
+ continue;
+ }
+
+ const intptr_t intersection =
+ FirstIntersectionWithAllocated(reg, unallocated);
+ if (intersection >= free_until) {
+ candidate = reg;
+ free_until = intersection;
+ TRACE_ALLOC(OS::Print(
+ "found %s for v%"Pd" with no interference on the back edge\n",
+ MakeRegisterLocation(candidate, Location::kDouble).Name(),
+ candidate));
+ break;
+ }
+ }
+ }
+ }
+
ASSERT(0 <= kMaxPosition);
if (free_until != kMaxPosition) {
for (intptr_t reg = 0; reg < NumberOfRegisters(); ++reg) {
@@ -1661,7 +1818,7 @@
TRACE_ALLOC(OS::Print("assigning free register "));
TRACE_ALLOC(MakeRegisterLocation(candidate, Location::kDouble).Print());
- TRACE_ALLOC(OS::Print(" to %"Pd"\n", unallocated->vreg()));
+ TRACE_ALLOC(OS::Print(" to v%"Pd"\n", unallocated->vreg()));
if (free_until != kMaxPosition) {
// There was an intersection. Split unallocated.
@@ -1764,7 +1921,7 @@
TRACE_ALLOC(OS::Print("assigning blocked register "));
TRACE_ALLOC(MakeRegisterLocation(candidate, Location::kDouble).Print());
- TRACE_ALLOC(OS::Print(" to live range %"Pd" until %"Pd"\n",
+ TRACE_ALLOC(OS::Print(" to live range v%"Pd" until %"Pd"\n",
unallocated->vreg(), blocked_at));
if (blocked_at < unallocated->End()) {
@@ -2070,6 +2227,7 @@
const GrowableArray<LiveRange*>& unallocated,
LiveRange** blocking_ranges,
bool* blocked_registers) {
+ ASSERT(number_of_registers <= kNumberOfCpuRegisters);
register_kind_ = register_kind;
number_of_registers_ = number_of_registers;
@@ -2097,7 +2255,7 @@
while (!unallocated_.is_empty()) {
LiveRange* range = unallocated_.RemoveLast();
const intptr_t start = range->Start();
- TRACE_ALLOC(OS::Print("Processing live range for vreg %"Pd" "
+ TRACE_ALLOC(OS::Print("Processing live range for v%"Pd" "
"starting at %"Pd"\n",
range->vreg(),
start));
@@ -2134,12 +2292,13 @@
void FlowGraphAllocator::ConnectSplitSiblings(LiveRange* parent,
BlockEntryInstr* source_block,
BlockEntryInstr* target_block) {
- TRACE_ALLOC(OS::Print("Connect source_block=%"Pd", target_block=%"Pd"\n",
+ TRACE_ALLOC(OS::Print("Connect v%"Pd" on the edge B%"Pd" -> B%"Pd"\n",
+ parent->vreg(),
source_block->block_id(),
target_block->block_id()));
if (parent->next_sibling() == NULL) {
// Nothing to connect. The whole range was allocated to the same location.
- TRACE_ALLOC(OS::Print("range %"Pd" has no siblings\n", parent->vreg()));
+ TRACE_ALLOC(OS::Print("range v%"Pd" has no siblings\n", parent->vreg()));
return;
}
@@ -2176,13 +2335,15 @@
range = range->next_sibling();
}
- TRACE_ALLOC(OS::Print("connecting [%"Pd", %"Pd") [",
- source_cover->Start(), source_cover->End()));
- TRACE_ALLOC(source.Print());
- TRACE_ALLOC(OS::Print("] to [%"Pd", %"Pd") [",
- target_cover->Start(), target_cover->End()));
- TRACE_ALLOC(target.Print());
- TRACE_ALLOC(OS::Print("]\n"));
+ TRACE_ALLOC(OS::Print("connecting v%"Pd" between [%"Pd", %"Pd") {%s} "
+ "to [%"Pd", %"Pd") {%s}\n",
+ parent->vreg(),
+ source_cover->Start(),
+ source_cover->End(),
+ source.Name(),
+ target_cover->Start(),
+ target_cover->End(),
+ target.Name()));
// Siblings were allocated to the same register.
if (source.Equals(target)) return;
diff --git a/runtime/vm/flow_graph_allocator.h b/runtime/vm/flow_graph_allocator.h
index b98fbb3..d88e6e1 100644
--- a/runtime/vm/flow_graph_allocator.h
+++ b/runtime/vm/flow_graph_allocator.h
@@ -17,6 +17,24 @@
class UseInterval;
class UsePosition;
+
+class ReachingDefs : public ValueObject {
+ public:
+ explicit ReachingDefs(const FlowGraph& flow_graph)
+ : flow_graph_(flow_graph),
+ phis_(10) { }
+
+ BitVector* Get(PhiInstr* phi);
+
+ private:
+ void AddPhi(PhiInstr* phi);
+ void Compute();
+
+ const FlowGraph& flow_graph_;
+ GrowableArray<PhiInstr*> phis_;
+};
+
+
class FlowGraphAllocator : public ValueObject {
public:
// Number of stack slots needed for a double spill slot.
@@ -94,9 +112,12 @@
// Visit instructions in the postorder and build live ranges for
// all SSA values.
void BuildLiveRanges();
- Instruction* ConnectOutgoingPhiMoves(BlockEntryInstr* block);
+ Instruction* ConnectOutgoingPhiMoves(BlockEntryInstr* block,
+ BitVector* interference_set);
void ProcessEnvironmentUses(BlockEntryInstr* block, Instruction* current);
- void ProcessOneInstruction(BlockEntryInstr* block, Instruction* instr);
+ void ProcessOneInstruction(BlockEntryInstr* block,
+ Instruction* instr,
+ BitVector* interference_set);
void ConnectIncomingPhiMoves(BlockEntryInstr* block);
void BlockLocation(Location loc, intptr_t from, intptr_t to);
void BlockRegisterLocation(Location loc,
@@ -214,6 +235,8 @@
const FlowGraph& flow_graph_;
+ ReachingDefs reaching_defs_;
+
// Set of SSA values that have unboxed mint representation. Indexed
// by SSA temp index.
BitVector* mint_values_;
@@ -299,7 +322,10 @@
class BlockInfo : public ZoneAllocated {
public:
explicit BlockInfo(BlockEntryInstr* entry)
- : entry_(entry), loop_(NULL), is_loop_header_(false) {
+ : entry_(entry),
+ loop_(NULL),
+ is_loop_header_(false),
+ backedge_interference_(NULL) {
}
BlockEntryInstr* entry() const { return entry_; }
@@ -307,6 +333,17 @@
// Returns true is this node is a header of a structural loop.
bool is_loop_header() const { return is_loop_header_; }
+ // Returns header of the innermost loop containing this block.
+ BlockInfo* loop_header() {
+ if (is_loop_header()) {
+ return this;
+ } else if (loop() != NULL) {
+ return loop();
+ } else {
+ return NULL;
+ }
+ }
+
// Innermost reducible loop containing this node. Loop headers point to
// outer loop not to themselves.
BlockInfo* loop() const { return loop_; }
@@ -326,6 +363,14 @@
intptr_t loop_id() const { return loop_id_; }
void set_loop_id(intptr_t loop_id) { loop_id_ = loop_id; }
+ BitVector* backedge_interference() const {
+ return backedge_interference_;
+ }
+
+ void set_backedge_interference(BitVector* backedge_interference) {
+ backedge_interference_ = backedge_interference;
+ }
+
private:
BlockEntryInstr* entry_;
BlockInfo* loop_;
@@ -334,6 +379,8 @@
BlockEntryInstr* last_block_;
intptr_t loop_id_;
+ BitVector* backedge_interference_;
+
DISALLOW_COPY_AND_ASSIGN(BlockInfo);
};
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index 96d4cb8..c9d67eb 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -1763,7 +1763,7 @@
}
if (node->constructor().IsFactory()) {
- if ((function_class.Name() == Symbols::ListImplementation()) &&
+ if ((function_class.Name() == Symbols::List()) &&
(function.name() == Symbols::ListFactory())) {
// If there are no arguments then the result is guaranteed to be a
// GrowableObjectArray. However if there is an argument the result
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 879799f..02d94fc 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -144,6 +144,8 @@
is_optimizing ? new StackmapTableBuilder() : NULL),
block_info_(block_order_.length()),
deopt_infos_(),
+ static_calls_target_table_(GrowableObjectArray::ZoneHandle(
+ GrowableObjectArray::New())),
is_optimizing_(is_optimizing),
may_reoptimize_(false),
bool_true_(Bool::ZoneHandle(Bool::True())),
@@ -282,6 +284,18 @@
}
+void FlowGraphCompiler::AddStaticCallTarget(const Function& func) {
+ ASSERT(Code::kSCallTableEntryLength == 3);
+ ASSERT(Code::kSCallTableOffsetEntry == 0);
+ static_calls_target_table_.Add(
+ Smi::Handle(Smi::New(assembler()->CodeSize())));
+ ASSERT(Code::kSCallTableFunctionEntry == 1);
+ static_calls_target_table_.Add(func);
+ ASSERT(Code::kSCallTableCodeEntry == 2);
+ static_calls_target_table_.Add(Code::Handle());
+}
+
+
void FlowGraphCompiler::AddDeoptIndexAtCall(intptr_t deopt_id,
intptr_t token_pos) {
ASSERT(is_optimizing());
@@ -396,6 +410,7 @@
code.set_deopt_info_array(array);
const Array& object_array =
Array::Handle(Array::MakeArray(builder.object_table()));
+ ASSERT(code.object_table() == Array::null());
code.set_object_table(object_array);
}
@@ -426,6 +441,13 @@
}
+void FlowGraphCompiler::FinalizeStaticCallTargetsTable(const Code& code) {
+ ASSERT(code.static_calls_target_table() == Array::null());
+ code.set_static_calls_target_table(
+ Array::Handle(Array::MakeArray(static_calls_target_table_)));
+}
+
+
// Returns 'true' if code generation for this function is complete, i.e.,
// no fall-through to regular code is needed.
bool FlowGraphCompiler::TryIntrinsify() {
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index 3a78f8c..f0236df 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -158,7 +158,7 @@
__ cmpl(kClassIdReg, Immediate(type_class.id()));
__ j(EQUAL, is_instance_lbl);
}
- if (type_class.raw() == Isolate::Current()->object_store()->list_class()) {
+ if (type_class.IsListClass()) {
GenerateListTypeCheck(kClassIdReg, is_instance_lbl);
}
return GenerateSubtype1TestCacheLookup(
@@ -1092,7 +1092,6 @@
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
- __ LoadObject(ECX, function);
__ LoadObject(EDX, 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.
@@ -1101,6 +1100,7 @@
&StubCode::CallStaticFunctionLabel(),
PcDescriptors::kFuncCall,
locs);
+ AddStaticCallTarget(function);
__ Drop(argument_count);
}
diff --git a/runtime/vm/flow_graph_compiler_ia32.h b/runtime/vm/flow_graph_compiler_ia32.h
index f949317..201b964 100644
--- a/runtime/vm/flow_graph_compiler_ia32.h
+++ b/runtime/vm/flow_graph_compiler_ia32.h
@@ -192,6 +192,7 @@
void FinalizeStackmaps(const Code& code);
void FinalizeVarDescriptors(const Code& code);
void FinalizeComments(const Code& code);
+ void FinalizeStaticCallTargetsTable(const Code& code);
const Bool& bool_true() const { return bool_true_; }
const Bool& bool_false() const { return bool_false_; }
@@ -227,6 +228,8 @@
Register index);
private:
+ void AddStaticCallTarget(const Function& function);
+
void GenerateDeferredCode();
void EmitInstructionPrologue(Instruction* instr);
@@ -320,6 +323,8 @@
GrowableArray<BlockInfo*> block_info_;
GrowableArray<CompilerDeoptInfo*> deopt_infos_;
GrowableArray<SlowPathCode*> slow_path_code_;
+ // Stores: [code offset, function, null(code)].
+ const GrowableObjectArray& static_calls_target_table_;
const bool is_optimizing_;
// Set to true if optimized code has IC calls.
bool may_reoptimize_;
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index eee2c68..a407051 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -158,7 +158,7 @@
__ cmpl(kClassIdReg, Immediate(type_class.id()));
__ j(EQUAL, is_instance_lbl);
}
- if (type_class.raw() == Isolate::Current()->object_store()->list_class()) {
+ if (type_class.IsListClass()) {
GenerateListTypeCheck(kClassIdReg, is_instance_lbl);
}
return GenerateSubtype1TestCacheLookup(
@@ -1096,7 +1096,6 @@
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
- __ LoadObject(RBX, function);
__ LoadObject(R10, 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.
@@ -1105,6 +1104,7 @@
&StubCode::CallStaticFunctionLabel(),
PcDescriptors::kFuncCall,
locs);
+ AddStaticCallTarget(function);
__ Drop(argument_count);
}
diff --git a/runtime/vm/flow_graph_compiler_x64.h b/runtime/vm/flow_graph_compiler_x64.h
index 146d9eb..3f74bc8 100644
--- a/runtime/vm/flow_graph_compiler_x64.h
+++ b/runtime/vm/flow_graph_compiler_x64.h
@@ -192,6 +192,7 @@
void FinalizeStackmaps(const Code& code);
void FinalizeVarDescriptors(const Code& code);
void FinalizeComments(const Code& code);
+ void FinalizeStaticCallTargetsTable(const Code& code);
const Bool& bool_true() const { return bool_true_; }
const Bool& bool_false() const { return bool_false_; }
@@ -227,6 +228,8 @@
Register index);
private:
+ void AddStaticCallTarget(const Function& function);
+
void GenerateDeferredCode();
void EmitInstructionPrologue(Instruction* instr);
@@ -320,6 +323,8 @@
GrowableArray<BlockInfo*> block_info_;
GrowableArray<CompilerDeoptInfo*> deopt_infos_;
GrowableArray<SlowPathCode*> slow_path_code_;
+ // Stores: [code offset, function, null(code)].
+ const GrowableObjectArray& static_calls_target_table_;
const bool is_optimizing_;
// Set to true if optimized code has IC calls.
bool may_reoptimize_;
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 6172ca5..2321f54 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -1107,6 +1107,43 @@
}
+StringCharCodeAtInstr* FlowGraphOptimizer::BuildStringCharCodeAt(
+ InstanceCallInstr* call,
+ intptr_t cid) {
+ Value* str = call->ArgumentAt(0)->value();
+ Value* index = call->ArgumentAt(1)->value();
+ AddCheckClass(call, str->Copy());
+ InsertBefore(call,
+ new CheckSmiInstr(index->Copy(), call->deopt_id()),
+ call->env(),
+ Definition::kEffect);
+ // If both index and string are constants, then do a compile-time check.
+ // TODO(srdjan): Remove once constant propagation handles bounds checks.
+ bool skip_check = false;
+ if (str->BindsToConstant() && index->BindsToConstant()) {
+ ConstantInstr* string_def = str->definition()->AsConstant();
+ const String& constant_string =
+ String::Cast(string_def->value());
+ ConstantInstr* index_def = index->definition()->AsConstant();
+ if (index_def->value().IsSmi()) {
+ intptr_t constant_index = Smi::Cast(index_def->value()).Value();
+ skip_check = (constant_index < constant_string.Length());
+ }
+ }
+ if (!skip_check) {
+ // Insert bounds check.
+ InsertBefore(call,
+ new CheckArrayBoundInstr(str->Copy(),
+ index->Copy(),
+ cid,
+ call),
+ call->env(),
+ Definition::kEffect);
+ }
+ return new StringCharCodeAtInstr(str, index, cid);
+}
+
+
// Inline only simple, frequently called core library methods.
bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
ASSERT(call->HasICData());
@@ -1124,42 +1161,24 @@
(ic_data.NumberOfChecks() == 1) &&
((class_ids[0] == kOneByteStringCid) ||
(class_ids[0] == kTwoByteStringCid))) {
- Value* str= call->ArgumentAt(0)->value();
- Value* index = call->ArgumentAt(1)->value();
- AddCheckClass(call, str->Copy());
- InsertBefore(call,
- new CheckSmiInstr(index->Copy(), call->deopt_id()),
- call->env(),
- Definition::kEffect);
- // If both index and string are constants, then do a compile-time check.
- // TODO(srdjan): Remove once constant propagation handles bounds checks.
- bool skip_check = false;
- if (str->BindsToConstant() && index->BindsToConstant()) {
- ConstantInstr* string_def = str->definition()->AsConstant();
- const String& constant_string =
- String::Cast(string_def->value());
- ConstantInstr* index_def = index->definition()->AsConstant();
- if (index_def->value().IsSmi()) {
- intptr_t constant_index = Smi::Cast(index_def->value()).Value();
- skip_check = (constant_index < constant_string.Length());
- }
- }
- if (!skip_check) {
- // Insert bounds check.
- InsertBefore(call,
- new CheckArrayBoundInstr(str->Copy(),
- index->Copy(),
- class_ids[0],
- call),
- call->env(),
- Definition::kEffect);
- }
- StringCharCodeAtInstr* instr =
- new StringCharCodeAtInstr(str, index, class_ids[0]);
+ StringCharCodeAtInstr* instr = BuildStringCharCodeAt(call, class_ids[0]);
call->ReplaceWith(instr, current_iterator());
RemovePushArguments(call);
return true;
}
+ if ((recognized_kind == MethodRecognizer::kStringBaseCharAt) &&
+ (ic_data.NumberOfChecks() == 1) &&
+ (class_ids[0] == kOneByteStringCid)) {
+ // TODO(fschneider): Handle TwoByteString.
+ StringCharCodeAtInstr* load_char_code =
+ BuildStringCharCodeAt(call, class_ids[0]);
+ InsertBefore(call, load_char_code, NULL, Definition::kValue);
+ StringFromCharCodeInstr* char_at =
+ new StringFromCharCodeInstr(new Value(load_char_code));
+ call->ReplaceWith(char_at, current_iterator());
+ RemovePushArguments(call);
+ return true;
+ }
if ((recognized_kind == MethodRecognizer::kIntegerToDouble) &&
(class_ids[0] == kSmiCid)) {
@@ -3302,6 +3321,12 @@
}
+void ConstantPropagator::VisitStringFromCharCode(
+ StringFromCharCodeInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
void ConstantPropagator::VisitLoadIndexed(LoadIndexedInstr* instr) {
SetValue(instr, non_constant_);
}
diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/flow_graph_optimizer.h
index 047dd0c..3c81b4a 100644
--- a/runtime/vm/flow_graph_optimizer.h
+++ b/runtime/vm/flow_graph_optimizer.h
@@ -68,6 +68,9 @@
bool TryInlineInstanceMethod(InstanceCallInstr* call);
+ StringCharCodeAtInstr* BuildStringCharCodeAt(InstanceCallInstr* call,
+ intptr_t cid);
+
void AddCheckClass(InstanceCallInstr* call, Value* value);
void InsertAfter(Instruction* prev,
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 21d220d..70a1ee8 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -241,9 +241,10 @@
const String& function_name = String::Handle(function.name());
const String& class_name = String::Handle(function_class.Name());
-#define RECOGNIZE_FUNCTION(test_class_name, test_function_name, enum_name) \
+#define RECOGNIZE_FUNCTION(test_class_name, test_function_name, enum_name, fp) \
if (CompareNames(lib, #test_function_name, function_name) && \
CompareNames(lib, #test_class_name, class_name)) { \
+ ASSERT(function.CheckSourceFingerprint(fp)); \
return k##enum_name; \
}
RECOGNIZED_LIST(RECOGNIZE_FUNCTION)
@@ -253,7 +254,7 @@
const char* MethodRecognizer::KindToCString(Kind kind) {
-#define KIND_TO_STRING(class_name, function_name, enum_name) \
+#define KIND_TO_STRING(class_name, function_name, enum_name, fp) \
if (kind == k##enum_name) return #enum_name;
RECOGNIZED_LIST(KIND_TO_STRING)
#undef KIND_TO_STRING
@@ -1128,6 +1129,16 @@
}
+RawAbstractType* StringFromCharCodeInstr::CompileType() const {
+ return Type::StringType();
+}
+
+
+intptr_t StringFromCharCodeInstr::ResultCid() const {
+ return kDynamicCid;
+}
+
+
RawAbstractType* LoadIndexedInstr::CompileType() const {
switch (class_id_) {
case kArrayCid:
@@ -2657,6 +2668,7 @@
}
}
+
#undef __
} // namespace dart
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index 23af66f..59ba34e 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -29,18 +29,21 @@
// TODO(srdjan): Add _ByteArrayBase, get:length.
-
+// TODO(srdjan): Unify with INTRINSIC_LIST.
+// (class-name, function-name, recognized enum, fingerprint).
+// See intrinsifier for fingerprint computation.
#define RECOGNIZED_LIST(V) \
- V(_ObjectArray, get:length, ObjectArrayLength) \
- V(_ImmutableArray, get:length, ImmutableArrayLength) \
- V(_GrowableObjectArray, get:length, GrowableArrayLength) \
- V(_GrowableObjectArray, get:capacity, GrowableArrayCapacity) \
- V(_StringBase, get:length, StringBaseLength) \
- V(_StringBase, get:isEmpty, StringBaseIsEmpty) \
- V(_StringBase, charCodeAt, StringBaseCharCodeAt) \
- V(_IntegerImplementation, toDouble, IntegerToDouble) \
- V(_Double, toInt, DoubleToInteger) \
- V(::, sqrt, MathSqrt) \
+ V(_ObjectArray, get:length, ObjectArrayLength, 405297088) \
+ V(_ImmutableArray, get:length, ImmutableArrayLength, 433698233) \
+ V(_GrowableObjectArray, get:length, GrowableArrayLength, 725548050) \
+ V(_GrowableObjectArray, get:capacity, GrowableArrayCapacity, 725548050) \
+ V(_StringBase, get:length, StringBaseLength, 320803993) \
+ V(_StringBase, get:isEmpty, StringBaseIsEmpty, 1065961093) \
+ V(_StringBase, charCodeAt, StringBaseCharCodeAt, 984449525) \
+ V(_StringBase, [], StringBaseCharAt, 1062366987) \
+ V(_IntegerImplementation, toDouble, IntegerToDouble, 1396338041) \
+ V(_Double, toInt, DoubleToInteger, 362666636) \
+ V(::, sqrt, MathSqrt, 2232519) \
// Class that recognizes the name and owner of a function and returns the
// corresponding enum. See RECOGNIZED_LIST above for list of recognizable
@@ -49,7 +52,7 @@
public:
enum Kind {
kUnknown,
-#define DEFINE_ENUM_LIST(class_name, function_name, enum_name) k##enum_name,
+#define DEFINE_ENUM_LIST(class_name, function_name, enum_name, fp) k##enum_name,
RECOGNIZED_LIST(DEFINE_ENUM_LIST)
#undef DEFINE_ENUM_LIST
};
@@ -264,7 +267,8 @@
M(UnaryMintOp) \
M(CheckArrayBound) \
M(Constraint) \
- M(StringCharCodeAt)
+ M(StringCharCodeAt) \
+ M(StringFromCharCode)
#define FORWARD_DECLARATION(type) class type##Instr;
@@ -1162,7 +1166,8 @@
: block_(block),
inputs_(num_inputs),
is_alive_(false),
- representation_(kTagged) {
+ representation_(kTagged),
+ reaching_defs_(NULL) {
for (intptr_t i = 0; i < num_inputs; ++i) {
inputs_.Add(NULL);
}
@@ -1223,6 +1228,14 @@
virtual void InferRange();
+ BitVector* reaching_defs() const {
+ return reaching_defs_;
+ }
+
+ void set_reaching_defs(BitVector* reaching_defs) {
+ reaching_defs_ = reaching_defs;
+ }
+
private:
friend class ConstantPropagator; // Direct access to inputs_.
@@ -1231,6 +1244,8 @@
bool is_alive_;
Representation representation_;
+ BitVector* reaching_defs_;
+
DISALLOW_COPY_AND_ASSIGN(PhiInstr);
};
@@ -2682,6 +2697,36 @@
};
+class StringFromCharCodeInstr : public TemplateDefinition<1> {
+ public:
+ explicit StringFromCharCodeInstr(Value* char_code) {
+ ASSERT(char_code != NULL);
+ ASSERT(char_code->definition()->IsStringCharCodeAt() &&
+ (char_code->definition()->AsStringCharCodeAt()->class_id() ==
+ kOneByteStringCid));
+ inputs_[0] = char_code;
+ }
+
+ DECLARE_INSTRUCTION(StringFromCharCode)
+ virtual RawAbstractType* CompileType() const;
+
+ Value* char_code() const { return inputs_[0]; }
+
+ virtual bool CanDeoptimize() const { return false; }
+
+ virtual bool HasSideEffect() const { return false; }
+
+ virtual intptr_t ResultCid() const;
+
+ virtual bool AttributesEqual(Instruction* other) const { return true; }
+
+ virtual bool AffectedBySideEffect() const { return false; }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StringFromCharCodeInstr);
+};
+
+
class LoadIndexedInstr : public TemplateDefinition<2> {
public:
LoadIndexedInstr(Value* array, Value* index, intptr_t class_id)
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 74b2a17..fd2c971 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -1124,6 +1124,30 @@
}
+LocationSummary* StringFromCharCodeInstr::MakeLocationSummary() const {
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ // TODO(fschneider): Allow immediate operands for the char code.
+ locs->set_in(0, Location::RequiresRegister());
+ locs->set_out(Location::RequiresRegister());
+ return locs;
+}
+
+
+void StringFromCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ Register char_code = locs()->in(0).reg();
+ Register result = locs()->out().reg();
+ __ movl(result,
+ Immediate(reinterpret_cast<uword>(Symbols::PredefinedAddress())));
+ __ movl(result, Address(result,
+ char_code,
+ TIMES_HALF_WORD_SIZE, // Char code is a smi.
+ Symbols::kNullCharId * kWordSize));
+}
+
+
LocationSummary* LoadIndexedInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index 32766ac1..6933867 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -992,6 +992,30 @@
}
+LocationSummary* StringFromCharCodeInstr::MakeLocationSummary() const {
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ // TODO(fschneider): Allow immediate operands for the char code.
+ locs->set_in(0, Location::RequiresRegister());
+ locs->set_out(Location::RequiresRegister());
+ return locs;
+}
+
+
+void StringFromCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ Register char_code = locs()->in(0).reg();
+ Register result = locs()->out().reg();
+ __ movq(result,
+ Immediate(reinterpret_cast<uword>(Symbols::PredefinedAddress())));
+ __ movq(result, Address(result,
+ char_code,
+ TIMES_HALF_WORD_SIZE, // Char code is a smi.
+ Symbols::kNullCharId * kWordSize));
+}
+
+
LocationSummary* LoadIndexedInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
diff --git a/runtime/vm/intrinsifier.cc b/runtime/vm/intrinsifier.cc
index 59adb5c..9e4188b 100644
--- a/runtime/vm/intrinsifier.cc
+++ b/runtime/vm/intrinsifier.cc
@@ -64,6 +64,8 @@
bool Intrinsifier::CanIntrinsify(const Function& function) {
if (!FLAG_intrinsify) return false;
if (function.IsClosureFunction()) return false;
+ // Can occur because of compile-all flag.
+ if (function.is_external()) return false;
// Intrinsic kind is set lazily below.
if (function.intrinsic_kind() == Function::kIsIntrinsic) return true;
if (function.intrinsic_kind() == Function::kIsNotIntrinsic) return false;
@@ -77,7 +79,7 @@
return false;
}
const char* class_name = String::Handle(function_class.Name()).ToCString();
-#define FIND_INTRINSICS(test_class_name, test_function_name, destination) \
+#define FIND_INTRINSICS(test_class_name, test_function_name, destination, fp) \
if (TestFunction(function, \
class_name, function_name, \
#test_class_name, #test_function_name)) { \
@@ -91,15 +93,17 @@
return false;
}
+
bool Intrinsifier::Intrinsify(const Function& function, Assembler* assembler) {
if (!CanIntrinsify(function)) return false;
const char* function_name = String::Handle(function.name()).ToCString();
const Class& function_class = Class::Handle(function.Owner());
const char* class_name = String::Handle(function_class.Name()).ToCString();
-#define FIND_INTRINSICS(test_class_name, test_function_name, destination) \
+#define FIND_INTRINSICS(test_class_name, test_function_name, destination, fp) \
if (TestFunction(function, \
class_name, function_name, \
#test_class_name, #test_function_name)) { \
+ ASSERT(function.CheckSourceFingerprint(fp)); \
return destination(assembler); \
} \
diff --git a/runtime/vm/intrinsifier.h b/runtime/vm/intrinsifier.h
index d127750..af4f8d4 100644
--- a/runtime/vm/intrinsifier.h
+++ b/runtime/vm/intrinsifier.h
@@ -10,88 +10,97 @@
namespace dart {
-// List of intrinsics: (class-name, function-name, intrinsification method).
+// List of intrinsics:
+// (class-name, function-name, intrinsification method, fingerprint).
+//
+// When adding a new function for intrinsification add a 0 as fingerprint,
+// build and run to get the correct fingerprint from the mismatch error.
#define INTRINSIC_LIST(V) \
- V(_IntegerImplementation, _addFromInteger, Integer_addFromInteger) \
- V(_IntegerImplementation, +, Integer_add) \
- V(_IntegerImplementation, _subFromInteger, Integer_subFromInteger) \
- V(_IntegerImplementation, -, Integer_sub) \
- V(_IntegerImplementation, _mulFromInteger, Integer_mulFromInteger) \
- V(_IntegerImplementation, *, Integer_mul) \
- V(_IntegerImplementation, %, Integer_modulo) \
- V(_IntegerImplementation, ~/, Integer_truncDivide) \
- V(_IntegerImplementation, unary-, Integer_negate) \
- V(_IntegerImplementation, _bitAndFromInteger, Integer_bitAndFromInteger) \
- V(_IntegerImplementation, &, Integer_bitAnd) \
- V(_IntegerImplementation, _bitOrFromInteger, Integer_bitOrFromInteger) \
- V(_IntegerImplementation, |, Integer_bitOr) \
- V(_IntegerImplementation, _bitXorFromInteger, Integer_bitXorFromInteger) \
- V(_IntegerImplementation, ^, Integer_bitXor) \
+ V(_IntegerImplementation, _addFromInteger, Integer_addFromInteger, 726019207)\
+ V(_IntegerImplementation, +, Integer_add, 13708438) \
+ V(_IntegerImplementation, _subFromInteger, Integer_subFromInteger, 726019207)\
+ V(_IntegerImplementation, -, Integer_sub, 284482664) \
+ V(_IntegerImplementation, _mulFromInteger, Integer_mulFromInteger, 726019207)\
+ V(_IntegerImplementation, *, Integer_mul, 486761895) \
+ V(_IntegerImplementation, %, Integer_modulo, 1370017357) \
+ V(_IntegerImplementation, ~/, Integer_truncDivide, 450435650) \
+ V(_IntegerImplementation, unary-, Integer_negate, 1734168384) \
+ V(_IntegerImplementation, _bitAndFromInteger, \
+ Integer_bitAndFromInteger, 726019207) \
+ V(_IntegerImplementation, &, Integer_bitAnd, 1267520437) \
+ V(_IntegerImplementation, _bitOrFromInteger, \
+ Integer_bitOrFromInteger, 726019207) \
+ V(_IntegerImplementation, |, Integer_bitOr, 249432836) \
+ V(_IntegerImplementation, _bitXorFromInteger, \
+ Integer_bitXorFromInteger, 726019207) \
+ V(_IntegerImplementation, ^, Integer_bitXor, 1177061571) \
V(_IntegerImplementation, \
_greaterThanFromInteger, \
- Integer_greaterThanFromInt) \
- V(_IntegerImplementation, >, Integer_greaterThan) \
- V(_IntegerImplementation, ==, Integer_equal) \
- V(_IntegerImplementation, _equalToInteger, Integer_equalToInteger) \
- V(_IntegerImplementation, <, Integer_lessThan) \
- V(_IntegerImplementation, <=, Integer_lessEqualThan) \
- V(_IntegerImplementation, >=, Integer_greaterEqualThan) \
- V(_IntegerImplementation, <<, Integer_shl) \
- V(_IntegerImplementation, >>, Integer_sar) \
- V(_Smi, ~, Smi_bitNegate) \
- V(_Double, >, Double_greaterThan) \
- V(_Double, >=, Double_greaterEqualThan) \
- V(_Double, <, Double_lessThan) \
- V(_Double, <=, Double_lessEqualThan) \
- V(_Double, ==, Double_equal) \
- V(_Double, +, Double_add) \
- V(_Double, -, Double_sub) \
- V(_Double, *, Double_mul) \
- V(_Double, /, Double_div) \
- V(_Double, get:isNaN, Double_getIsNaN) \
- V(_Double, get:isNegative, Double_getIsNegative) \
- V(_Double, _mulFromInteger, Double_mulFromInteger) \
- V(_Double, .fromInteger, Double_fromInteger) \
- V(_Double, toInt, Double_toInt) \
- V(_ObjectArray, ., ObjectArray_Allocate) \
- V(_ObjectArray, get:length, Array_getLength) \
- V(_ObjectArray, [], Array_getIndexed) \
- V(_ObjectArray, []=, Array_setIndexed) \
- V(_GrowableObjectArray, .fromObjectArray, GArray_Allocate) \
- V(_GrowableObjectArray, get:length, GrowableArray_getLength) \
- V(_GrowableObjectArray, get:capacity, GrowableArray_getCapacity) \
- V(_GrowableObjectArray, [], GrowableArray_getIndexed) \
- V(_GrowableObjectArray, []=, GrowableArray_setIndexed) \
- V(_GrowableObjectArray, _setLength, GrowableArray_setLength) \
- V(_GrowableObjectArray, _setData, GrowableArray_setData) \
- V(_GrowableObjectArray, add, GrowableArray_add) \
- V(_ImmutableArray, [], ImmutableArray_getIndexed) \
- V(_ImmutableArray, get:length, ImmutableArray_getLength) \
- V(::, sqrt, Math_sqrt) \
- V(::, sin, Math_sin) \
- V(::, cos, Math_cos) \
- V(Object, ==, Object_equal) \
- V(_FixedSizeArrayIterator, get:hasNext, FixedSizeArrayIterator_getHasNext) \
- V(_FixedSizeArrayIterator, next, FixedSizeArrayIterator_next) \
- V(_StringBase, get:hashCode, String_getHashCode) \
- V(_StringBase, get:isEmpty, String_getIsEmpty) \
- V(_StringBase, get:length, String_getLength) \
- V(_StringBase, charCodeAt, String_charCodeAt) \
- V(_ByteArrayBase, get:length, ByteArrayBase_getLength) \
- V(_Int8Array, [], Int8Array_getIndexed) \
- V(_Int8Array, []=, Int8Array_setIndexed) \
- V(_Uint8Array, [], Uint8Array_getIndexed) \
- V(_Uint8Array, []=, Uint8Array_setIndexed) \
- V(_Int16Array, [], Int16Array_getIndexed) \
- V(_Uint16Array, [], Uint16Array_getIndexed) \
- V(_Int32Array, [], Int32Array_getIndexed) \
- V(_Uint32Array, [], Uint32Array_getIndexed) \
- V(_Int64Array, [], Int64Array_getIndexed) \
- V(_Uint64Array, [], Uint64Array_getIndexed) \
- V(_Float32Array, [], Float32Array_getIndexed) \
- V(_Float32Array, []=, Float32Array_setIndexed) \
- V(_Float64Array, [], Float64Array_getIndexed) \
- V(_Float64Array, []=, Float64Array_setIndexed) \
+ Integer_greaterThanFromInt, 79222670) \
+ V(_IntegerImplementation, >, Integer_greaterThan, 319553701) \
+ V(_IntegerImplementation, ==, Integer_equal, 1163202222) \
+ V(_IntegerImplementation, _equalToInteger, Integer_equalToInteger, 79222670) \
+ V(_IntegerImplementation, <, Integer_lessThan, 1306209983) \
+ V(_IntegerImplementation, <=, Integer_lessEqualThan, 458673122) \
+ V(_IntegerImplementation, >=, Integer_greaterEqualThan, 459596643) \
+ V(_IntegerImplementation, <<, Integer_shl, 1586407617) \
+ V(_IntegerImplementation, >>, Integer_sar, 130211175) \
+ V(_Smi, ~, Smi_bitNegate, 882629793) \
+ V(_Double, >, Double_greaterThan, 1821658410) \
+ V(_Double, >=, Double_greaterEqualThan, 1317118885) \
+ V(_Double, <, Double_lessThan, 177557761) \
+ V(_Double, <=, Double_lessEqualThan, 1316195364) \
+ V(_Double, ==, Double_equal, 1896071176) \
+ V(_Double, +, Double_add, 1137022234) \
+ V(_Double, -, Double_sub, 1425469940) \
+ V(_Double, *, Double_mul, 1865672692) \
+ V(_Double, /, Double_div, 1832148629) \
+ V(_Double, get:isNaN, Double_getIsNaN, 54462366) \
+ V(_Double, get:isNegative, Double_getIsNegative, 54462366) \
+ V(_Double, _mulFromInteger, Double_mulFromInteger, 795128) \
+ V(_Double, .fromInteger, Double_fromInteger, 842078193) \
+ V(_Double, toInt, Double_toInt, 362666636) \
+ V(_ObjectArray, ., ObjectArray_Allocate, 577949617) \
+ V(_ObjectArray, get:length, Array_getLength, 405297088) \
+ V(_ObjectArray, [], Array_getIndexed, 71937385) \
+ V(_ObjectArray, []=, Array_setIndexed, 255863719) \
+ V(_GrowableObjectArray, .fromObjectArray, GArray_Allocate, 989879928) \
+ V(_GrowableObjectArray, get:length, GrowableArray_getLength, 725548050) \
+ V(_GrowableObjectArray, get:capacity, GrowableArray_getCapacity, 725548050) \
+ V(_GrowableObjectArray, [], GrowableArray_getIndexed, 581838973) \
+ V(_GrowableObjectArray, []=, GrowableArray_setIndexed, 1048007636) \
+ V(_GrowableObjectArray, _setLength, GrowableArray_setLength, 796709584) \
+ V(_GrowableObjectArray, _setData, GrowableArray_setData, 477312179) \
+ V(_GrowableObjectArray, add, GrowableArray_add, 1776744235) \
+ V(_ImmutableArray, [], ImmutableArray_getIndexed, 486821199) \
+ V(_ImmutableArray, get:length, ImmutableArray_getLength, 433698233) \
+ V(::, sqrt, Math_sqrt, 2232519) \
+ V(::, sin, Math_sin, 837187616) \
+ V(::, cos, Math_cos, 548880317) \
+ V(Object, ==, Object_equal, 1512068535) \
+ V(_FixedSizeArrayIterator, get:hasNext, \
+ FixedSizeArrayIterator_getHasNext, 1847855366) \
+ V(_FixedSizeArrayIterator, next, FixedSizeArrayIterator_next, 1739352783) \
+ V(_StringBase, get:hashCode, String_getHashCode, 320803993) \
+ V(_StringBase, get:isEmpty, String_getIsEmpty, 1065961093) \
+ V(_StringBase, get:length, String_getLength, 320803993) \
+ V(_StringBase, charCodeAt, String_charCodeAt, 984449525) \
+ V(_ByteArrayBase, get:length, ByteArrayBase_getLength, 1856909152) \
+ V(_Int8Array, [], Int8Array_getIndexed, 239810357) \
+ V(_Int8Array, []=, Int8Array_setIndexed, 1469038436) \
+ V(_Uint8Array, [], Uint8Array_getIndexed, 1635923899) \
+ V(_Uint8Array, []=, Uint8Array_setIndexed, 1619321522) \
+ V(_Int16Array, [], Int16Array_getIndexed, 2090761657) \
+ V(_Uint16Array, [], Uint16Array_getIndexed, 289929708) \
+ V(_Int32Array, [], Int32Array_getIndexed, 589442411) \
+ V(_Uint32Array, [], Uint32Array_getIndexed, 1474116947) \
+ V(_Int64Array, [], Int64Array_getIndexed, 1506836119) \
+ V(_Uint64Array, [], Uint64Array_getIndexed, 1856952148) \
+ V(_Float32Array, [], Float32Array_getIndexed, 1167607283) \
+ V(_Float32Array, []=, Float32Array_setIndexed, 1270729544) \
+ V(_Float64Array, [], Float64Array_getIndexed, 1363897161) \
+ V(_Float64Array, []=, Float64Array_setIndexed, 283625119) \
+ V(_ExternalUint8Array, [], ExternalUint8Array_getIndexed, 632699940) \
// Forward declarations.
class Assembler;
@@ -106,7 +115,7 @@
static bool CanIntrinsify(const Function& function);
private:
-#define DECLARE_FUNCTION(test_class_name, test_function_name, destination) \
+#define DECLARE_FUNCTION(test_class_name, test_function_name, destination, fp) \
static bool destination(Assembler* assembler);
INTRINSIC_LIST(DECLARE_FUNCTION)
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc
index cf47309..5675214 100644
--- a/runtime/vm/intrinsifier_ia32.cc
+++ b/runtime/vm/intrinsifier_ia32.cc
@@ -538,22 +538,19 @@
// * EBX has the index into the array.
// EBX contains the SMI index which is shifted by 1.
__ SmiUntag(EBX);
- // Move EBX into EDI.
+ // Free EBX for the value since we want a byte register.
__ movl(EDI, EBX);
- // Load the value into EBX.
__ movl(EBX, Address(ESP, + 1 * kWordSize)); // Value.
- // If EBX is not an Smi, jump to fall through.
__ testl(EBX, Immediate(kSmiTagMask));
__ j(NOT_ZERO, &fall_through, Assembler::kNearJump);
__ SmiUntag(EBX);
- // Add 128 to EBX to bring it into 0..FF.
+ // Check that the value is a byte. Add 128 to EBX to bring it into
+ // the range 0..FF.
__ addl(EBX, Immediate(128));
__ cmpl(EBX, Immediate(0xFF));
- // If EBX is too large an Int8, jump to fall through.
__ j(ABOVE, &fall_through, Assembler::kNearJump);
- // Remove addition.
+ // Undo addition.
__ subl(EBX, Immediate(128));
- // Store BL into array EAX[EDI] = BL.
__ movb(FieldAddress(EAX, EDI, TIMES_1, Int8Array::data_offset()), BL);
__ ret();
__ Bind(&fall_through);
@@ -585,18 +582,15 @@
// * EBX has the index into the array.
// EBX contains the SMI index which is shifted by 1.
__ SmiUntag(EBX);
- // Move EBX into EDI.
+ // Free EBX for the value since we want a byte register.
__ movl(EDI, EBX);
- // Load the value into EBX.
__ movl(EBX, Address(ESP, + 1 * kWordSize)); // Value.
- // If EBX is not an Smi, jump to fall through.
__ testl(EBX, Immediate(kSmiTagMask));
__ j(NOT_ZERO, &fall_through, Assembler::kNearJump);
__ SmiUntag(EBX);
- // If EBX is too large an Uint8, jump to fall through.
+ // Check that the value is a byte.
__ cmpl(EBX, Immediate(0xFF));
__ j(ABOVE, &fall_through, Assembler::kNearJump);
- // Store BL into array EAX[EDI] = BL.
__ movb(FieldAddress(EAX, EDI, TIMES_1, Uint8Array::data_offset()), BL);
__ ret();
__ Bind(&fall_through);
@@ -792,6 +786,20 @@
}
+bool Intrinsifier::ExternalUint8Array_getIndexed(Assembler* assembler) {
+ Label fall_through;
+ TestByteArrayIndex(assembler, &fall_through);
+ __ SmiUntag(EBX);
+ __ movl(EAX, FieldAddress(EAX, ExternalUint8Array::external_data_offset()));
+ __ movl(EAX, Address(EAX, ExternalByteArrayData<uint8_t>::data_offset()));
+ __ movzxb(EAX, Address(EAX, EBX, TIMES_1, 0));
+ __ SmiTag(EAX);
+ __ ret();
+ __ Bind(&fall_through);
+ return false;
+}
+
+
// Tests if two top most arguments are smis, jumps to label not_smi if not.
// Topmost argument is in EAX.
static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) {
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index 5f3f96d..8d52b6a 100644
--- a/runtime/vm/intrinsifier_x64.cc
+++ b/runtime/vm/intrinsifier_x64.cc
@@ -471,6 +471,26 @@
bool Intrinsifier::Int8Array_setIndexed(Assembler* assembler) {
Label fall_through;
+ // Verify that the array index is valid.
+ TestByteArraySetIndex(assembler, &fall_through);
+ // After TestByteArraySetIndex:
+ // * RAX has the base address of the byte array.
+ // * R12 has the index into the array.
+ // R12 contains the SMI index which is shifted by 1.
+ __ SmiUntag(R12);
+ __ movq(RDI, Address(RSP, + 1 * kWordSize)); // Value.
+ __ testq(RDI, Immediate(kSmiTagMask));
+ __ j(NOT_ZERO, &fall_through, Assembler::kNearJump);
+ __ SmiUntag(RDI);
+ // Check that the value is a byte. Add 128 to the value to bring it into
+ // the range 0..FF.
+ __ addq(RDI, Immediate(128));
+ __ cmpq(RDI, Immediate(0xFF));
+ __ j(ABOVE, &fall_through, Assembler::kNearJump);
+ // Undo addition.
+ __ subq(RDI, Immediate(128));
+ __ movb(FieldAddress(RAX, R12, TIMES_1, Uint8Array::data_offset()), RDI);
+ __ ret();
__ Bind(&fall_through);
return false;
}
@@ -478,6 +498,22 @@
bool Intrinsifier::Uint8Array_setIndexed(Assembler* assembler) {
Label fall_through;
+ // Verify that the array index is valid.
+ TestByteArraySetIndex(assembler, &fall_through);
+ // After TestByteArraySetIndex:
+ // * RAX has the base address of the byte array.
+ // * R12 has the index into the array.
+ // R12 contains the SMI index which is shifted by 1.
+ __ SmiUntag(R12);
+ __ movq(RDI, Address(RSP, + 1 * kWordSize)); // Value.
+ __ testq(RDI, Immediate(kSmiTagMask));
+ __ j(NOT_ZERO, &fall_through, Assembler::kNearJump);
+ __ SmiUntag(RDI);
+ // Check that value is a byte.
+ __ cmpq(RDI, Immediate(0xFF));
+ __ j(ABOVE, &fall_through, Assembler::kNearJump);
+ __ movb(FieldAddress(RAX, R12, TIMES_1, Uint8Array::data_offset()), RDI);
+ __ ret();
__ Bind(&fall_through);
return false;
}
@@ -700,6 +736,20 @@
}
+bool Intrinsifier::ExternalUint8Array_getIndexed(Assembler* assembler) {
+ Label fall_through;
+ TestByteArrayIndex(assembler, &fall_through);
+ __ SmiUntag(R12);
+ __ movq(RAX, FieldAddress(RAX, ExternalUint8Array::external_data_offset()));
+ __ movq(RAX, Address(RAX, ExternalByteArrayData<uint8_t>::data_offset()));
+ __ movzxb(RAX, Address(RAX, R12, TIMES_1, 0));
+ __ SmiTag(RAX);
+ __ ret();
+ __ Bind(&fall_through);
+ return false;
+}
+
+
// Tests if two top most arguments are smis, jumps to label not_smi if not.
// Topmost argument is in RAX.
static void TestBothArgumentsSmis(Assembler* assembler, Label* not_smi) {
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index af8f5e3..6b9178d 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -17,7 +17,6 @@
#include "vm/object_store.h"
#include "vm/parser.h"
#include "vm/port.h"
-#include "vm/random.h"
#include "vm/stack_frame.h"
#include "vm/stub_code.h"
#include "vm/symbols.h"
@@ -150,7 +149,6 @@
heap_(NULL),
object_store_(NULL),
top_context_(Context::null()),
- random_seed_(Random::kDefaultRandomSeed),
top_exit_frame_info_(0),
init_callback_data_(NULL),
library_tag_handler_(NULL),
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 76afa3e..5849640 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -145,9 +145,6 @@
return OFFSET_OF(Isolate, top_context_);
}
- int32_t random_seed() const { return random_seed_; }
- void set_random_seed(int32_t value) { random_seed_ = value; }
-
uword top_exit_frame_info() const { return top_exit_frame_info_; }
void set_top_exit_frame_info(uword value) { top_exit_frame_info_ = value; }
static intptr_t top_exit_frame_info_offset() {
@@ -326,7 +323,6 @@
Heap* heap_;
ObjectStore* object_store_;
RawContext* top_context_;
- int32_t random_seed_;
uword top_exit_frame_info_;
void* init_callback_data_;
Dart_LibraryTagHandler library_tag_handler_;
diff --git a/runtime/vm/isolate_test.cc b/runtime/vm/isolate_test.cc
index 2aadf6d..9812840 100644
--- a/runtime/vm/isolate_test.cc
+++ b/runtime/vm/isolate_test.cc
@@ -23,7 +23,7 @@
// callback has been set by the embedder when an isolate is spawned.
TEST_CASE(IsolateSpawn) {
const char* kScriptChars =
- "#import('dart:isolate');\n"
+ "import 'dart:isolate';\n"
"void entry() {}\n"
"int testMain() {\n"
" try {\n"
diff --git a/runtime/vm/locations.h b/runtime/vm/locations.h
index 4522b1a..0c2bc09 100644
--- a/runtime/vm/locations.h
+++ b/runtime/vm/locations.h
@@ -277,6 +277,12 @@
return value_ == other.value_;
}
+ // If current location is constant might return something that
+ // is not equal to any Kind.
+ Kind kind() const {
+ return KindField::decode(value_);
+ }
+
private:
explicit Location(uword value) : value_(value) { }
@@ -287,12 +293,6 @@
return PayloadField::decode(value_);
}
- // If current location is constant might return something that
- // is not equal to any Kind.
- Kind kind() const {
- return KindField::decode(value_);
- }
-
typedef BitField<Kind, 0, kBitsForKind> KindField;
typedef BitField<uword, kBitsForKind, kBitsForPayload> PayloadField;
diff --git a/runtime/vm/native_entry_test.cc b/runtime/vm/native_entry_test.cc
index 6f945b4..8c58b66 100644
--- a/runtime/vm/native_entry_test.cc
+++ b/runtime/vm/native_entry_test.cc
@@ -58,14 +58,15 @@
// Test code patching.
void TestStaticCallPatching(Dart_NativeArguments args) {
Dart_EnterScope();
- uword target_address = 0;
- Function& target_function = Function::Handle();
DartFrameIterator iterator;
iterator.NextFrame(); // Skip native call.
StackFrame* static_caller_frame = iterator.NextFrame();
- CodePatcher::GetStaticCallAt(static_caller_frame->pc(),
- &target_function,
- &target_address);
+ uword target_address =
+ CodePatcher::GetStaticCallTargetAt(static_caller_frame->pc());
+ const Code& code = Code::Handle(static_caller_frame->LookupDartCode());
+ const Function& target_function =
+ Function::Handle(code.GetStaticCallTargetFunctionAt(
+ static_caller_frame->pc()));
EXPECT(String::Handle(target_function.name()).
Equals(String::Handle(String::New("NativePatchStaticCall"))));
const uword function_entry_address =
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 5dc09dd..6867359 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -408,6 +408,8 @@
isolate->object_store()->set_array_class(cls);
cls = Class::NewStringClass(kOneByteStringCid);
isolate->object_store()->set_one_byte_string_class(cls);
+ cls = Class::NewStringClass(kTwoByteStringCid);
+ isolate->object_store()->set_two_byte_string_class(cls);
// Allocate and initialize the empty_array instance.
{
@@ -516,17 +518,6 @@
}
-RawClass* Object::CreateAndRegisterInterface(const char* cname,
- const Script& script,
- const Library& lib) {
- const String& name = String::Handle(Symbols::New(cname));
- const Class& cls = Class::Handle(
- Class::NewInterface(name, script, Scanner::kDummyTokenIndex));
- lib.AddClass(cls);
- return cls.raw();
-}
-
-
void Object::RegisterClass(const Class& cls,
const String& name,
const Library& lib) {
@@ -590,6 +581,10 @@
cls = Class::NewStringClass(kOneByteStringCid);
object_store->set_one_byte_string_class(cls);
+ // Pre-allocate the TwoByteString class needed by the symbol table.
+ cls = Class::NewStringClass(kTwoByteStringCid);
+ object_store->set_two_byte_string_class(cls);
+
// Setup the symbol table for the symbols created in the isolate.
Symbols::SetupSymbolTable(isolate);
@@ -650,8 +645,7 @@
RegisterPrivateClass(cls, name, core_lib);
pending_classes.Add(cls, Heap::kOld);
- cls = Class::NewStringClass(kTwoByteStringCid);
- object_store->set_two_byte_string_class(cls);
+ cls = object_store->two_byte_string_class(); // Was allocated above.
name = Symbols::TwoByteString();
RegisterPrivateClass(cls, name, core_lib);
pending_classes.Add(cls, Heap::kOld);
@@ -886,7 +880,9 @@
type = Type::NewNonParameterizedType(cls);
object_store->set_string_type(type);
- cls = CreateAndRegisterInterface("List", script, core_lib);
+ name = Symbols::New("List");
+ cls = Class::New<Instance>(name, script, Scanner::kDummyTokenIndex);
+ RegisterClass(cls, name, core_lib);
pending_classes.Add(cls, Heap::kOld);
object_store->set_list_class(cls);
@@ -2038,6 +2034,11 @@
}
+bool Class::IsListClass() const {
+ return raw() == Isolate::Current()->object_store()->list_class();
+}
+
+
bool Class::IsCanonicalSignatureClass() const {
const Function& function = Function::Handle(signature_function());
return (!function.IsNull() && (function.signature_class() == raw()));
@@ -2476,7 +2477,12 @@
const char* UnresolvedClass::ToCString() const {
- return "UnresolvedClass";
+ const char* format = "unresolved class '%s'";
+ const char* cname = String::Handle(Name()).ToCString();
+ intptr_t len = OS::SNPrint(NULL, 0, format, cname) + 1;
+ char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+ OS::SNPrint(chars, len, format, cname);
+ return chars;
}
@@ -4180,6 +4186,45 @@
}
+// Construct fingerprint from token stream. The token stream contains also
+// arguments.
+int32_t Function::SourceFingerprint() const {
+ uint32_t result = String::Handle(Signature()).Hash();
+ TokenStream::Iterator tokens_iterator(TokenStream::Handle(
+ Script::Handle(script()).tokens()), token_pos());
+ Object& obj = Object::Handle();
+ String& literal = String::Handle();
+ while (tokens_iterator.CurrentPosition() < end_token_pos()) {
+ uint32_t val = 0;
+ obj = tokens_iterator.CurrentToken();
+ if (obj.IsSmi()) {
+ val = Smi::Cast(obj).Value();
+ } else {
+ literal = tokens_iterator.MakeLiteralToken(obj);
+ val = literal.Hash();
+ }
+ result = 31 * result + val;
+ tokens_iterator.Advance();
+ }
+ result = result & ((static_cast<uint32_t>(1) << 31) - 1);
+ ASSERT(result <= static_cast<uint32_t>(kMaxInt32));
+ return result;
+}
+
+
+bool Function::CheckSourceFingerprint(intptr_t fp) const {
+ if (SourceFingerprint() != fp) {
+ OS::Print("FP mismatch while recogbnizing method %s:"
+ " expecting %"Pd" found %d\n",
+ ToFullyQualifiedCString(),
+ fp,
+ SourceFingerprint());
+ return false;
+ }
+ return true;
+}
+
+
const char* Function::ToCString() const {
const char* static_str = is_static() ? " static" : "";
const char* abstract_str = is_abstract() ? " abstract" : "";
@@ -7002,8 +7047,41 @@
}
-void Code::set_resolved_static_calls(const GrowableObjectArray& val) const {
- StorePointer(&raw_ptr()->resolved_static_calls_, val.raw());
+void Code::set_static_calls_target_table(const Array& value) const {
+ StorePointer(&raw_ptr()->static_calls_target_table_, value.raw());
+}
+
+
+RawFunction* Code::GetStaticCallTargetFunctionAt(uword pc) const {
+ RawObject* raw_code_offset =
+ reinterpret_cast<RawObject*>(Smi::New(pc - EntryPoint()));
+ const Array& array =
+ Array::Handle(raw_ptr()->static_calls_target_table_);
+ for (intptr_t i = 0; i < array.Length(); i += kSCallTableEntryLength) {
+ if (array.At(i) == raw_code_offset) {
+ Function& function = Function::Handle();
+ function ^= array.At(i + kSCallTableFunctionEntry);
+ return function.raw();
+ }
+ }
+ return Function::null();
+}
+
+
+void Code::SetStaticCallTargetCodeAt(uword pc, const Code& code) const {
+ RawObject* raw_code_offset =
+ reinterpret_cast<RawObject*>(Smi::New(pc - EntryPoint()));
+ const Array& array =
+ Array::Handle(raw_ptr()->static_calls_target_table_);
+ for (intptr_t i = 0; i < array.Length(); i += kSCallTableEntryLength) {
+ if (array.At(i) == raw_code_offset) {
+ ASSERT(code.IsNull() ||
+ (code.function() == array.At(i + kSCallTableFunctionEntry)));
+ array.SetAt(i + kSCallTableCodeEntry, code);
+ return;
+ }
+ }
+ UNREACHABLE();
}
@@ -7276,12 +7354,11 @@
deopt_ids->Clear();
const PcDescriptors& descriptors =
PcDescriptors::Handle(this->pc_descriptors());
- Function& function = Function::Handle();
for (intptr_t i = 0; i < descriptors.Length(); i++) {
if (descriptors.DescriptorKind(i) == PcDescriptors::kFuncCall) {
// Static call.
- uword target_addr;
- CodePatcher::GetStaticCallAt(descriptors.PC(i), &function, &target_addr);
+ const uword target_addr =
+ CodePatcher::GetStaticCallTargetAt(descriptors.PC(i));
if (target_addr == StubCode::CallStaticFunctionEntryPoint()) {
deopt_ids->Add(descriptors.DeoptId(i));
}
@@ -8977,18 +9054,21 @@
if (IsResolved()) {
const AbstractTypeArguments& type_arguments =
AbstractTypeArguments::Handle(arguments());
+ const char* class_name;
+ if (HasResolvedTypeClass()) {
+ class_name = String::Handle(
+ Class::Handle(type_class()).Name()).ToCString();
+ } else {
+ class_name = UnresolvedClass::Handle(unresolved_class()).ToCString();
+ }
if (type_arguments.IsNull()) {
const char* format = "Type: class '%s'";
- const char* class_name =
- String::Handle(Class::Handle(type_class()).Name()).ToCString();
intptr_t len = OS::SNPrint(NULL, 0, format, class_name) + 1;
char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
OS::SNPrint(chars, len, format, class_name);
return chars;
} else {
const char* format = "Type: class '%s', args:[%s]";
- const char* class_name =
- String::Handle(Class::Handle(type_class()).Name()).ToCString();
const char* args_cstr =
AbstractTypeArguments::Handle(arguments()).ToCString();
intptr_t len = OS::SNPrint(NULL, 0, format, class_name, args_cstr) + 1;
@@ -9875,11 +9955,11 @@
hash_ ^= hash_ >> 11;
hash_ += hash_ << 15;
hash_ = hash_ & ((static_cast<intptr_t>(1) << bits) - 1);
- ASSERT(hash_ >= 0);
+ ASSERT(hash_ <= static_cast<uint32_t>(kMaxInt32));
return hash_ == 0 ? 1 : hash_;
}
private:
- intptr_t hash_;
+ uint32_t hash_;
};
@@ -9927,7 +10007,7 @@
}
-intptr_t String::Hash(const uint32_t* characters, intptr_t len) {
+intptr_t String::Hash(const int32_t* characters, intptr_t len) {
return HashImpl(characters, len);
}
@@ -9990,36 +10070,37 @@
}
-bool String::Equals(const char* str) const {
- ASSERT(str != NULL);
- intptr_t len = strlen(str);
- for (intptr_t i = 0; i < this->Length(); ++i) {
- if (*str == '\0') {
+bool String::Equals(const char* cstr) const {
+ ASSERT(cstr != NULL);
+ CodePointIterator it(*this);
+ intptr_t len = strlen(cstr);
+ while (it.Next()) {
+ if (*cstr == '\0') {
// Lengths don't match.
return false;
}
int32_t ch;
- intptr_t consumed = Utf8::Decode(reinterpret_cast<const uint8_t*>(str),
+ intptr_t consumed = Utf8::Decode(reinterpret_cast<const uint8_t*>(cstr),
len,
&ch);
- if (consumed == 0 || this->CharAt(i) != ch) {
+ if (consumed == 0 || it.Current() != ch) {
return false;
}
- str += consumed;
+ cstr += consumed;
len -= consumed;
}
- return *str == '\0';
+ return *cstr == '\0';
}
-bool String::Equals(const uint8_t* characters, intptr_t len) const {
+bool String::Equals(const uint8_t* latin1_array, intptr_t len) const {
if (len != this->Length()) {
// Lengths don't match.
return false;
}
for (intptr_t i = 0; i < len; i++) {
- if (this->CharAt(i) != characters[i]) {
+ if (this->CharAt(i) != latin1_array[i]) {
return false;
}
}
@@ -10027,14 +10108,14 @@
}
-bool String::Equals(const uint16_t* characters, intptr_t len) const {
+bool String::Equals(const uint16_t* utf16_array, intptr_t len) const {
if (len != this->Length()) {
// Lengths don't match.
return false;
}
for (intptr_t i = 0; i < len; i++) {
- if (this->CharAt(i) != characters[i]) {
+ if (this->CharAt(i) != utf16_array[i]) {
return false;
}
}
@@ -10042,16 +10123,17 @@
}
-bool String::Equals(const uint32_t* characters, intptr_t len) const {
- if (len != this->Length()) {
- // Lengths don't match.
- return false;
- }
-
- for (intptr_t i = 0; i < len; i++) {
- if (this->CharAt(i) != static_cast<int32_t>(characters[i])) {
+bool String::Equals(const int32_t* utf32_array, intptr_t len) const {
+ CodePointIterator it(*this);
+ intptr_t i = 0;
+ while (it.Next()) {
+ if (it.Current() != static_cast<int32_t>(utf32_array[i])) {
return false;
}
+ ++i;
+ }
+ if (i != len) {
+ return false;
}
return true;
}
@@ -10121,7 +10203,7 @@
}
return strobj.raw();
}
- ASSERT((type == Utf8::kBMP) || (type == Utf8::kSMP));
+ ASSERT((type == Utf8::kBMP) || (type == Utf8::kSupplementary));
const String& strobj = String::Handle(TwoByteString::New(len, space));
NoGCScope no_gc;
Utf8::DecodeToUTF16(utf8_array, array_len,
@@ -10147,7 +10229,7 @@
}
-RawString* String::New(const uint32_t* utf32_array,
+RawString* String::New(const int32_t* utf32_array,
intptr_t array_len,
Heap::Space space) {
bool is_one_byte_string = true;
@@ -10512,10 +10594,9 @@
ASSERT(!str.IsNull());
bool has_mapping = false;
int32_t dst_max = 0;
- intptr_t len = str.Length();
- // TODO(cshapiro): assume a transform is required, rollback if not.
- for (intptr_t i = 0; i < len; ++i) {
- int32_t src = str.CharAt(i);
+ CodePointIterator it(str);
+ while (it.Next()) {
+ int32_t src = it.Current();
int32_t dst = mapping(src);
if (src != dst) {
has_mapping = true;
@@ -10545,6 +10626,25 @@
}
+bool String::CodePointIterator::Next() {
+ ASSERT(index_ >= -1);
+ ASSERT(index_ < str_.Length());
+ int d = Utf16::Length(ch_);
+ if (index_ == (str_.Length() - d)) {
+ return false;
+ }
+ index_ += d;
+ ch_ = str_.CharAt(index_);
+ if (Utf16::IsLeadSurrogate(ch_) && (index_ != (str_.Length() - 1))) {
+ int32_t ch2 = str_.CharAt(index_ + 1);
+ if (Utf16::IsTrailSurrogate(ch2)) {
+ ch_ = Utf16::Decode(ch_, ch2);
+ }
+ }
+ return true;
+}
+
+
RawOneByteString* OneByteString::EscapeSpecialCharacters(const String& str,
bool raw_str) {
intptr_t len = str.Length();
@@ -10683,7 +10783,7 @@
}
-RawOneByteString* OneByteString::New(const uint32_t* characters,
+RawOneByteString* OneByteString::New(const int32_t* characters,
intptr_t len,
Heap::Space space) {
const String& result = String::Handle(OneByteString::New(len, space));
@@ -10818,7 +10918,7 @@
RawTwoByteString* TwoByteString::New(intptr_t utf16_len,
- const uint32_t* utf32_array,
+ const int32_t* utf32_array,
intptr_t array_len,
Heap::Space space) {
ASSERT((array_len > 0) && (utf16_len >= array_len));
@@ -10829,7 +10929,7 @@
for (intptr_t i = 0; i < array_len; ++i) {
if (utf32_array[i] > 0xffff) {
ASSERT(j < (utf16_len - 1));
- Utf8::ConvertUTF32ToUTF16(utf32_array[i], CharAddr(result, j));
+ Utf16::Encode(utf32_array[i], CharAddr(result, j));
j += 2;
} else {
ASSERT(j < utf16_len);
@@ -10887,10 +10987,20 @@
ASSERT(!str.IsNull());
intptr_t len = str.Length();
const String& result = String::Handle(TwoByteString::New(len, space));
- for (intptr_t i = 0; i < len; ++i) {
- int32_t ch = mapping(str.CharAt(i));
- ASSERT(ch >= 0 && ch <= 0xFFFF);
- *CharAddr(result, i) = ch;
+ String::CodePointIterator it(str);
+ intptr_t i = 0;
+ while (it.Next()) {
+ int32_t src = it.Current();
+ int32_t dst = mapping(src);
+ ASSERT(dst >= 0 && dst <= 0x10FFFF);
+ intptr_t len = Utf16::Length(dst);
+ if (len == 1) {
+ *CharAddr(result, i) = dst;
+ } else {
+ ASSERT(len == 2);
+ Utf16::Encode(dst, CharAddr(result, i));
+ }
+ i += len;
}
return TwoByteString::raw(result);
}
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 07cb5bf..e40d545 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -366,9 +366,6 @@
private:
static void InitializeObject(uword address, intptr_t id, intptr_t size);
- static RawClass* CreateAndRegisterInterface(const char* cname,
- const Script& script,
- const Library& lib);
static void RegisterClass(const Class& cls,
const String& name,
const Library& lib);
@@ -605,6 +602,9 @@
// Check if this class represents the 'Object' class.
bool IsObjectClass() const { return id() == kInstanceCid; }
+ // Check if this class represents the 'List' class.
+ bool IsListClass() const;
+
// Check if this class represents a signature class.
bool IsSignatureClass() const {
return signature_function() != Object::null();
@@ -1433,6 +1433,13 @@
const Function& parent,
intptr_t token_pos);
+ // Slow function, use in asserts to track changes in important library
+ // functions.
+ int32_t SourceFingerprint() const;
+
+ // Return false and report an error if the fingerprint does not match.
+ bool CheckSourceFingerprint(intptr_t fp) const;
+
static const int kCtorPhaseInit = 1 << 0;
static const int kCtorPhaseBody = 1 << 1;
static const int kCtorPhaseAll = (kCtorPhaseInit | kCtorPhaseBody);
@@ -2486,10 +2493,22 @@
void set_stackmaps(const Array& maps) const;
RawStackmap* GetStackmap(uword pc, Array* stackmaps, Stackmap* map) const;
- RawGrowableObjectArray* resolved_static_calls() const {
- return raw_ptr()->resolved_static_calls_;
+ enum {
+ kSCallTableOffsetEntry = 0,
+ kSCallTableFunctionEntry = 1,
+ kSCallTableCodeEntry = 2,
+ kSCallTableEntryLength = 3,
+ };
+
+ void set_static_calls_target_table(const Array& value) const;
+ RawArray* static_calls_target_table() const {
+ return raw_ptr()->static_calls_target_table_;
}
- void set_resolved_static_calls(const GrowableObjectArray& val) const;
+
+ // Returns null if there is no static call at 'pc'.
+ RawFunction* GetStaticCallTargetFunctionAt(uword pc) const;
+ // Aborts if there is no static call at 'pc'.
+ void SetStaticCallTargetCodeAt(uword pc, const Code& code) const;
class Comments : public ZoneAllocated {
public:
@@ -3708,6 +3727,29 @@
static const intptr_t kSizeofRawString = sizeof(RawObject) + (2 * kWordSize);
static const intptr_t kMaxElements = kSmiMax / kTwoByteChar;
+ class CodePointIterator : public ValueObject {
+ public:
+ explicit CodePointIterator(const String& str)
+ : str_(str),
+ index_(-1),
+ ch_(-1) {
+ }
+
+ int32_t Current() {
+ ASSERT(index_ >= 0);
+ ASSERT(index_ < str_.Length());
+ return ch_;
+ }
+
+ bool Next();
+
+ private:
+ const String& str_;
+ intptr_t index_;
+ int32_t ch_;
+ DISALLOW_IMPLICIT_CONSTRUCTORS(CodePointIterator);
+ };
+
intptr_t Length() const { return Smi::Value(raw_ptr()->length_); }
static intptr_t length_offset() { return OFFSET_OF(RawString, length_); }
@@ -3716,7 +3758,7 @@
static intptr_t Hash(const String& str, intptr_t begin_index, intptr_t len);
static intptr_t Hash(const uint8_t* characters, intptr_t len);
static intptr_t Hash(const uint16_t* characters, intptr_t len);
- static intptr_t Hash(const uint32_t* characters, intptr_t len);
+ static intptr_t Hash(const int32_t* characters, intptr_t len);
int32_t CharAt(intptr_t index) const;
@@ -3726,10 +3768,18 @@
inline bool Equals(const String& str,
intptr_t begin_index, // begin index on 'str'.
intptr_t len) const; // len on 'str'.
- bool Equals(const char* str) const;
+
+ // Compares to a '\0' terminated array of UTF-8 encoded characters.
+ bool Equals(const char* cstr) const;
+
+ // Compares to an array of UTF-8 encoded characters.
bool Equals(const uint8_t* characters, intptr_t len) const;
+
+ // Compares to an array of UTF-16 encoded characters.
bool Equals(const uint16_t* characters, intptr_t len) const;
- bool Equals(const uint32_t* characters, intptr_t len) const;
+
+ // Compares to an array of UTF-32 encoded characters.
+ bool Equals(const int32_t* characters, intptr_t len) const;
virtual bool Equals(const Instance& other) const;
@@ -3791,7 +3841,7 @@
Heap::Space space = Heap::kNew);
// Creates a new String object from an array of UTF-32 encoded characters.
- static RawString* New(const uint32_t* utf32_array,
+ static RawString* New(const int32_t* utf32_array,
intptr_t array_len,
Heap::Space space = Heap::kNew);
@@ -3937,7 +3987,7 @@
static RawOneByteString* New(const uint16_t* characters,
intptr_t len,
Heap::Space space);
- static RawOneByteString* New(const uint32_t* characters,
+ static RawOneByteString* New(const int32_t* characters,
intptr_t len,
Heap::Space space);
static RawOneByteString* New(const String& str,
@@ -4020,7 +4070,7 @@
intptr_t len,
Heap::Space space);
static RawTwoByteString* New(intptr_t utf16_len,
- const uint32_t* characters,
+ const int32_t* characters,
intptr_t len,
Heap::Space space);
static RawTwoByteString* New(const String& str,
@@ -4515,7 +4565,7 @@
static const intptr_t kMaxElements = kSmiMax / kBytesPerElement;
static intptr_t data_offset() {
- return length_offset() + kWordSize;
+ return OFFSET_OF(RawInt8Array, data_);
}
static intptr_t InstanceSize() {
@@ -4567,7 +4617,7 @@
static const intptr_t kMaxElements = kSmiMax / kBytesPerElement;
static intptr_t data_offset() {
- return length_offset() + kWordSize;
+ return OFFSET_OF(RawUint8Array, data_);
}
static intptr_t InstanceSize() {
@@ -4619,7 +4669,7 @@
static const intptr_t kMaxElements = kSmiMax / kBytesPerElement;
static intptr_t data_offset() {
- return length_offset() + kWordSize;
+ return OFFSET_OF(RawInt16Array, data_);
}
static intptr_t InstanceSize() {
@@ -4671,7 +4721,7 @@
static const intptr_t kMaxElements = kSmiMax / kBytesPerElement;
static intptr_t data_offset() {
- return length_offset() + kWordSize;
+ return OFFSET_OF(RawUint16Array, data_);
}
static intptr_t InstanceSize() {
@@ -4723,7 +4773,7 @@
static const intptr_t kMaxElements = kSmiMax / kBytesPerElement;
static intptr_t data_offset() {
- return length_offset() + kWordSize;
+ return OFFSET_OF(RawInt32Array, data_);
}
static intptr_t InstanceSize() {
@@ -4775,7 +4825,7 @@
static const intptr_t kMaxElements = kSmiMax / kBytesPerElement;
static intptr_t data_offset() {
- return length_offset() + kWordSize;
+ return OFFSET_OF(RawUint32Array, data_);
}
static intptr_t InstanceSize() {
@@ -4827,7 +4877,7 @@
static const intptr_t kMaxElements = kSmiMax / kBytesPerElement;
static intptr_t data_offset() {
- return length_offset() + kWordSize;
+ return OFFSET_OF(RawInt64Array, data_);
}
static intptr_t InstanceSize() {
@@ -4879,7 +4929,7 @@
static const intptr_t kMaxElements = kSmiMax / kBytesPerElement;
static intptr_t data_offset() {
- return length_offset() + kWordSize;
+ return OFFSET_OF(RawUint64Array, data_);
}
static intptr_t InstanceSize() {
@@ -4931,7 +4981,7 @@
static const intptr_t kMaxElements = kSmiMax / kBytesPerElement;
static intptr_t data_offset() {
- return length_offset() + kWordSize;
+ return OFFSET_OF(RawFloat32Array, data_);
}
static intptr_t InstanceSize() {
@@ -4988,7 +5038,7 @@
}
static intptr_t data_offset() {
- return length_offset() + kWordSize;
+ return OFFSET_OF(RawFloat64Array, data_);
}
static intptr_t InstanceSize(intptr_t len) {
@@ -5107,6 +5157,10 @@
return RoundedAllocationSize(sizeof(RawExternalUint8Array));
}
+ static intptr_t external_data_offset() {
+ return OFFSET_OF(RawExternalUint8Array, external_data_);
+ }
+
static RawExternalUint8Array* New(uint8_t* data,
intptr_t len,
void* peer,
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 354c11c..f91f5d6 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -5,6 +5,7 @@
#include "platform/assert.h"
#include "vm/assembler.h"
#include "vm/bigint_operations.h"
+#include "vm/class_finalizer.h"
#include "vm/isolate.h"
#include "vm/object.h"
#include "vm/object_store.h"
@@ -273,6 +274,48 @@
}
+TEST_CASE(StringCompareTo) {
+ const String& abcd = String::Handle(String::New("abcd"));
+ const String& abce = String::Handle(String::New("abce"));
+ EXPECT_EQ(0, abcd.CompareTo(abcd));
+ EXPECT_EQ(0, abce.CompareTo(abce));
+ EXPECT(abcd.CompareTo(abce) < 0);
+ EXPECT(abce.CompareTo(abcd) > 0);
+
+ const int kMonkeyLen = 4;
+ const uint8_t monkey_utf8[kMonkeyLen] = { 0xf0, 0x9f, 0x90, 0xb5 };
+ const String& monkey_face =
+ String::Handle(String::New(monkey_utf8, kMonkeyLen));
+ const int kDogLen = 4;
+ // 0x1f436 DOG FACE.
+ const uint8_t dog_utf8[kDogLen] = { 0xf0, 0x9f, 0x90, 0xb6 };
+ const String& dog_face = String::Handle(String::New(dog_utf8, kDogLen));
+ EXPECT_EQ(0, monkey_face.CompareTo(monkey_face));
+ EXPECT_EQ(0, dog_face.CompareTo(dog_face));
+ EXPECT(monkey_face.CompareTo(dog_face) < 0);
+ EXPECT(dog_face.CompareTo(monkey_face) > 0);
+
+ const int kDominoLen = 4;
+ // 0x1f036 DOMINO TILE HORIZONTAL-00-05.
+ const uint8_t domino_utf8[kDominoLen] = { 0xf0, 0x9f, 0x80, 0xb6 };
+ const String& domino = String::Handle(String::New(domino_utf8, kDominoLen));
+ EXPECT_EQ(0, domino.CompareTo(domino));
+ EXPECT(domino.CompareTo(dog_face) < 0);
+ EXPECT(domino.CompareTo(monkey_face) < 0);
+ EXPECT(dog_face.CompareTo(domino) > 0);
+ EXPECT(monkey_face.CompareTo(domino) > 0);
+
+ EXPECT(abcd.CompareTo(monkey_face) < 0);
+ EXPECT(abce.CompareTo(monkey_face) < 0);
+ EXPECT(abcd.CompareTo(domino) < 0);
+ EXPECT(abce.CompareTo(domino) < 0);
+ EXPECT(domino.CompareTo(abcd) > 0);
+ EXPECT(domino.CompareTo(abcd) > 0);
+ EXPECT(monkey_face.CompareTo(abce) > 0);
+ EXPECT(monkey_face.CompareTo(abce) > 0);
+}
+
+
TEST_CASE(Mint) {
// On 64-bit architectures a Smi is stored in a 64 bit word. A Midint cannot
// be allocated if it does fit into a Smi.
@@ -559,7 +602,7 @@
EXPECT_EQ(false, str1.StartsWith(str3));
}
- const uint32_t four_chars[] = { 'C', 0xFF, 'h', 0xFFFF, 'a', 0x10FFFF, 'r' };
+ const int32_t four_chars[] = { 'C', 0xFF, 'h', 0xFFFF, 'a', 0x10FFFF, 'r' };
const String& four_str = String::Handle(String::New(four_chars, 7));
EXPECT_EQ(four_str.Hash(), four_str.Hash());
EXPECT(four_str.IsTwoByteString());
@@ -587,7 +630,7 @@
// Create a 1-byte string from an array of 4-byte elements.
{
- const uint32_t char32[] = { 0x00, 0x1F, 0x7F };
+ const int32_t char32[] = { 0x00, 0x1F, 0x7F };
const String& str8 = String::Handle(String::New(char32, 3));
EXPECT(str8.IsOneByteString());
EXPECT(!str8.IsTwoByteString());
@@ -598,7 +641,7 @@
// Create a 2-byte string from an array of 4-byte elements.
{
- const uint32_t char32[] = { 0, 0x7FFF, 0xFFFF };
+ const int32_t char32[] = { 0, 0x7FFF, 0xFFFF };
const String& str16 = String::Handle(String::New(char32, 3));
EXPECT(!str16.IsOneByteString());
EXPECT(str16.IsTwoByteString());
@@ -943,7 +986,7 @@
EXPECT(str1.IsOneByteString());
EXPECT_EQ(0, str1.Length());
- uint32_t four[] = { 0x1D4D5, 0x1D4DE, 0x1D4E4, 0x1D4E1 };
+ int32_t four[] = { 0x1D4D5, 0x1D4DE, 0x1D4E4, 0x1D4E1 };
intptr_t four_len = sizeof(four) / sizeof(four[0]);
intptr_t expected_len = (four_len * 2);
const String& str2 = String::Handle(String::New(four, four_len));
@@ -988,8 +1031,8 @@
array3.SetAt(2, str2);
const String& str7 = String::Handle(String::ConcatAll(array3));
EXPECT(str7.IsTwoByteString());
- uint32_t fourfour[] = { 0x1D4D5, 0x1D4DE, 0x1D4E4, 0x1D4E1,
- 0x1D4D5, 0x1D4DE, 0x1D4E4, 0x1D4E1 };
+ int32_t fourfour[] = { 0x1D4D5, 0x1D4DE, 0x1D4E4, 0x1D4E1,
+ 0x1D4D5, 0x1D4DE, 0x1D4E4, 0x1D4E1 };
intptr_t fourfour_len = sizeof(fourfour) / sizeof(fourfour[0]);
EXPECT_EQ((fourfour_len * 2), str7.Length());
const String& fourfour_str =
@@ -999,13 +1042,13 @@
// Concatenate non-empty strings built from 4-byte elements.
{
- const uint32_t one[] = { 0x105D0, 0x105D9, 0x105D9, 0x105DF };
+ const int32_t one[] = { 0x105D0, 0x105D9, 0x105D9, 0x105DF };
intptr_t one_len = sizeof(one) / sizeof(one[0]);
const String& onestr = String::Handle(String::New(one, one_len));
EXPECT(onestr.IsTwoByteString());
EXPECT_EQ((one_len *2), onestr.Length());
- const uint32_t two[] = { 0x105E6, 0x105D5, 0x105D5, 0x105D9, 0x105D9 };
+ const int32_t two[] = { 0x105E6, 0x105D5, 0x105D5, 0x105D9, 0x105D9 };
intptr_t two_len = sizeof(two) / sizeof(two[0]);
const String& twostr = String::Handle(String::New(two, two_len));
EXPECT(twostr.IsTwoByteString());
@@ -1015,8 +1058,8 @@
const String& str1 = String::Handle(String::Concat(onestr, twostr));
EXPECT(str1.IsTwoByteString());
- const uint32_t one_two[] = { 0x105D0, 0x105D9, 0x105D9, 0x105DF,
- 0x105E6, 0x105D5, 0x105D5, 0x105D9, 0x105D9 };
+ const int32_t one_two[] = { 0x105D0, 0x105D9, 0x105D9, 0x105DF,
+ 0x105E6, 0x105D5, 0x105D5, 0x105D9, 0x105D9 };
intptr_t one_two_len = sizeof(one_two) / sizeof(one_two[0]);
EXPECT_EQ((one_two_len * 2), str1.Length());
const String& one_two_str =
@@ -1025,8 +1068,8 @@
const String& str2 = String::Handle(String::Concat(twostr, onestr));
EXPECT(str2.IsTwoByteString());
- const uint32_t two_one[] = { 0x105E6, 0x105D5, 0x105D5, 0x105D9, 0x105D9,
- 0x105D0, 0x105D9, 0x105D9, 0x105DF };
+ const int32_t two_one[] = { 0x105E6, 0x105D5, 0x105D5, 0x105D9, 0x105D9,
+ 0x105D0, 0x105D9, 0x105D9, 0x105DF };
intptr_t two_one_len = sizeof(two_one) / sizeof(two_one[0]);
EXPECT_EQ((two_one_len * 2), str2.Length());
const String& two_one_str =
@@ -1060,10 +1103,10 @@
array3.SetAt(2, onestr);
const String& str5 = String::Handle(String::ConcatAll(array3));
EXPECT(str5.IsTwoByteString());
- const uint32_t one_two_one[] = { 0x105D0, 0x105D9, 0x105D9, 0x105DF,
- 0x105E6, 0x105D5, 0x105D5, 0x105D9,
- 0x105D9,
- 0x105D0, 0x105D9, 0x105D9, 0x105DF };
+ const int32_t one_two_one[] = { 0x105D0, 0x105D9, 0x105D9, 0x105DF,
+ 0x105E6, 0x105D5, 0x105D5, 0x105D9,
+ 0x105D9,
+ 0x105D0, 0x105D9, 0x105D9, 0x105DF };
intptr_t one_two_one_len = sizeof(one_two_one) / sizeof(one_two_one[0]);
EXPECT_EQ((one_two_one_len * 2), str5.Length());
const String& one_two_one_str =
@@ -1077,11 +1120,11 @@
array4.SetAt(2, twostr);
const String& str6 = String::Handle(String::ConcatAll(array4));
EXPECT(str6.IsTwoByteString());
- const uint32_t two_one_two[] = { 0x105E6, 0x105D5, 0x105D5, 0x105D9,
- 0x105D9,
- 0x105D0, 0x105D9, 0x105D9, 0x105DF,
- 0x105E6, 0x105D5, 0x105D5, 0x105D9,
- 0x105D9 };
+ const int32_t two_one_two[] = { 0x105E6, 0x105D5, 0x105D5, 0x105D9,
+ 0x105D9,
+ 0x105D0, 0x105D9, 0x105D9, 0x105DF,
+ 0x105E6, 0x105D5, 0x105D5, 0x105D9,
+ 0x105D9 };
intptr_t two_one_two_len = sizeof(two_one_two) / sizeof(two_one_two[0]);
EXPECT_EQ((two_one_two_len * 2), str6.Length());
const String& two_one_two_str =
@@ -1312,7 +1355,8 @@
}
}
- // Create a SMP 2-byte string from a UTF-8 string literal.
+ // Create a 2-byte string with supplementary characters from a UTF-8
+ // string literal.
{
const char* src =
"\xF0\x9D\x91\xA0\xF0\x9D\x91\xA1"
@@ -1385,6 +1429,37 @@
}
+TEST_CASE(StringEqualsUtf8) {
+ const char* onesrc = "abc";
+ const String& onestr = String::Handle(String::New(onesrc));
+ EXPECT(onestr.IsOneByteString());
+ EXPECT(!onestr.Equals(""));
+ EXPECT(!onestr.Equals("a"));
+ EXPECT(!onestr.Equals("ab"));
+ EXPECT(onestr.Equals("abc"));
+ EXPECT(!onestr.Equals("abcd"));
+
+ const char* twosrc = "\xD7\x90\xD7\x91\xD7\x92";
+ const String& twostr = String::Handle(String::New(twosrc));
+ EXPECT(twostr.IsTwoByteString());
+ EXPECT(!twostr.Equals(""));
+ EXPECT(!twostr.Equals("\xD7\x90"));
+ EXPECT(!twostr.Equals("\xD7\x90\xD7\x91"));
+ EXPECT(twostr.Equals("\xD7\x90\xD7\x91\xD7\x92"));
+ EXPECT(!twostr.Equals("\xD7\x90\xD7\x91\xD7\x92\xD7\x93"));
+
+ const char* foursrc = "\xF0\x90\x8E\xA0\xF0\x90\x8E\xA1\xF0\x90\x8E\xA2";
+ const String& fourstr = String::Handle(String::New(foursrc));
+ EXPECT(fourstr.IsTwoByteString());
+ EXPECT(!fourstr.Equals(""));
+ EXPECT(!fourstr.Equals("\xF0\x90\x8E\xA0"));
+ EXPECT(!fourstr.Equals("\xF0\x90\x8E\xA0\xF0\x90\x8E\xA1"));
+ EXPECT(fourstr.Equals("\xF0\x90\x8E\xA0\xF0\x90\x8E\xA1\xF0\x90\x8E\xA2"));
+ EXPECT(!fourstr.Equals("\xF0\x90\x8E\xA0\xF0\x90\x8E\xA1"
+ "\xF0\x90\x8E\xA2\xF0\x90\x8E\xA3"));
+}
+
+
TEST_CASE(ExternalOneByteString) {
uint8_t characters[] = { 0xF6, 0xF1, 0xE9 };
intptr_t len = ARRAY_SIZE(characters);
@@ -1501,10 +1576,36 @@
EXPECT_EQ(one.raw(), ein_symbol.raw());
EXPECT(one.raw() != eins.raw());
- uint32_t char32[] = { 'E', 'l', 'f' };
- String& elf = String::Handle(Symbols::New(char32, 3));
- EXPECT(elf.IsSymbol());
- EXPECT_EQ(elf.raw(), Symbols::New("Elf"));
+ uint16_t char16[] = { 'E', 'l', 'f' };
+ String& elf1 = String::Handle(Symbols::New(char16, 3));
+ int32_t char32[] = { 'E', 'l', 'f' };
+ String& elf2 = String::Handle(Symbols::New(char32, 3));
+ EXPECT(elf1.IsSymbol());
+ EXPECT(elf2.IsSymbol());
+ EXPECT_EQ(elf1.raw(), Symbols::New("Elf"));
+ EXPECT_EQ(elf2.raw(), Symbols::New("Elf"));
+}
+
+
+TEST_CASE(SymbolUnicode) {
+ uint16_t monkey_utf16[] = { 0xd83d, 0xdc35 }; // Unicode Monkey Face.
+ String& monkey = String::Handle(Symbols::New(monkey_utf16, 2));
+ EXPECT(monkey.IsSymbol());
+ const char monkey_utf8[] = {0xf0, 0x9f, 0x90, 0xb5, 0};
+ EXPECT_EQ(monkey.raw(), Symbols::New(monkey_utf8));
+
+ int32_t kMonkeyFace = 0x1f435;
+ String& monkey2 = String::Handle(Symbols::FromCharCode(kMonkeyFace));
+ EXPECT_EQ(monkey.raw(), monkey2.raw());
+
+ // Unicode cat face with tears of joy.
+ int32_t kCatFaceWithTearsOfJoy = 0x1f639;
+ String& cat = String::Handle(Symbols::FromCharCode(kCatFaceWithTearsOfJoy));
+
+ uint16_t cat_utf16[] = { 0xd83d, 0xde39 };
+ String& cat2 = String::Handle(Symbols::New(cat_utf16, 2));
+ EXPECT(cat2.IsSymbol());
+ EXPECT_EQ(cat2.raw(), cat.raw());
}
@@ -1552,6 +1653,61 @@
}
+TEST_CASE(StringCodePointIterator) {
+ const String& str0 = String::Handle(String::New(""));
+ String::CodePointIterator it0(str0);
+ EXPECT(!it0.Next());
+
+ const String& str1 = String::Handle(String::New(" \xc3\xa7 "));
+ String::CodePointIterator it1(str1);
+ EXPECT(it1.Next());
+ EXPECT_EQ(' ', it1.Current());
+ EXPECT(it1.Next());
+ EXPECT_EQ(0xE7, it1.Current());
+ EXPECT(it1.Next());
+ EXPECT_EQ(' ', it1.Current());
+ EXPECT(!it1.Next());
+
+ const String& str2 = String::Handle(String::New("\xD7\x92\xD7\x9C"
+ "\xD7\xA2\xD7\x93"
+ "\xD7\x91\xD7\xA8"
+ "\xD7\x9B\xD7\x94"));
+ String::CodePointIterator it2(str2);
+ EXPECT(it2.Next());
+ EXPECT_EQ(0x5D2, it2.Current());
+ EXPECT(it2.Next());
+ EXPECT_EQ(0x5DC, it2.Current());
+ EXPECT(it2.Next());
+ EXPECT_EQ(0x5E2, it2.Current());
+ EXPECT(it2.Next());
+ EXPECT_EQ(0x5D3, it2.Current());
+ EXPECT(it2.Next());
+ EXPECT_EQ(0x5D1, it2.Current());
+ EXPECT(it2.Next());
+ EXPECT_EQ(0x5E8, it2.Current());
+ EXPECT(it2.Next());
+ EXPECT_EQ(0x5DB, it2.Current());
+ EXPECT(it2.Next());
+ EXPECT_EQ(0x5D4, it2.Current());
+ EXPECT(!it2.Next());
+
+ const String& str3 = String::Handle(String::New("\xF0\x9D\x91\xA0"
+ "\xF0\x9D\x91\xA1"
+ "\xF0\x9D\x91\xA2"
+ "\xF0\x9D\x91\xA3"));
+ String::CodePointIterator it3(str3);
+ EXPECT(it3.Next());
+ EXPECT_EQ(0x1D460, it3.Current());
+ EXPECT(it3.Next());
+ EXPECT_EQ(0x1D461, it3.Current());
+ EXPECT(it3.Next());
+ EXPECT_EQ(0x1D462, it3.Current());
+ EXPECT(it3.Next());
+ EXPECT_EQ(0x1D463, it3.Current());
+ EXPECT(!it3.Next());
+}
+
+
TEST_CASE(GrowableObjectArray) {
const int kArrayLen = 5;
Smi& value = Smi::Handle();
@@ -3035,6 +3191,64 @@
EXPECT(weak2.value() == Object::null());
}
+
+static RawFunction* GetFunction(const Class& cls, const char* name) {
+ const Function& result = Function::Handle(cls.LookupDynamicFunction(
+ String::Handle(String::New(name))));
+ ASSERT(!result.IsNull());
+ return result.raw();
+}
+
+
+TEST_CASE(FunctionSourceFingerprint) {
+ const char* kScriptChars =
+ "class A {\n"
+ " void test1(int a) {\n"
+ " return a > 1 ? a + 1 : a;\n"
+ " }\n"
+ " void test2(int a) {\n"
+ " return a > 1 ? a + 1 : a;\n"
+ " }\n"
+ " void test3(a) {\n"
+ " return a > 1 ? a + 1 : a;\n"
+ " }\n"
+ " void test4(b) {\n"
+ " return b > 1 ? b + 1 : b;\n"
+ " }\n"
+ " void test5(b) {\n"
+ " return b > 1 ? b - 1 : b;\n"
+ " }\n"
+ " void test6(b) {\n"
+ " return b > 1 ? b - 2 : b;\n"
+ " }\n"
+ " void test7(b) {\n"
+ " return b > 1 ?\n"
+ " b - 2 : b;\n"
+ " }\n"
+ "}";
+ TestCase::LoadTestScript(kScriptChars, NULL);
+ EXPECT(ClassFinalizer::FinalizePendingClasses());
+ const String& name = String::Handle(String::New(TestCase::url()));
+ const Library& lib = Library::Handle(Library::LookupLibrary(name));
+ EXPECT(!lib.IsNull());
+
+ const Class& class_a = Class::Handle(
+ lib.LookupClass(String::Handle(Symbols::New("A"))));
+ const Function& test1 = Function::Handle(GetFunction(class_a, "test1"));
+ const Function& test2 = Function::Handle(GetFunction(class_a, "test2"));
+ const Function& test3 = Function::Handle(GetFunction(class_a, "test3"));
+ const Function& test4 = Function::Handle(GetFunction(class_a, "test4"));
+ const Function& test5 = Function::Handle(GetFunction(class_a, "test5"));
+ const Function& test6 = Function::Handle(GetFunction(class_a, "test6"));
+ const Function& test7 = Function::Handle(GetFunction(class_a, "test7"));
+ EXPECT_EQ(test1.SourceFingerprint(), test2.SourceFingerprint());
+ EXPECT_NE(test1.SourceFingerprint(), test3.SourceFingerprint());
+ EXPECT_NE(test3.SourceFingerprint(), test4.SourceFingerprint());
+ EXPECT_NE(test4.SourceFingerprint(), test5.SourceFingerprint());
+ EXPECT_NE(test5.SourceFingerprint(), test6.SourceFingerprint());
+ EXPECT_EQ(test6.SourceFingerprint(), test7.SourceFingerprint());
+}
+
#endif // defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64).
} // namespace dart
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 4c9027b..3273891 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -35,6 +35,8 @@
"Warning on legacy getter syntax");
DEFINE_FLAG(bool, strict_function_literals, false,
"enforce new function literal rules");
+DEFINE_FLAG(bool, fail_legacy_abstract, false,
+ "error on explicit use of abstract on class members");
static void CheckedModeHandler(bool value) {
FLAG_enable_asserts = value;
@@ -2543,7 +2545,8 @@
const intptr_t type_pos = TokenPos();
const AbstractType& type = AbstractType::Handle(
ParseType(ClassFinalizer::kTryResolve));
- if (type.IsTypeParameter() || type.IsDynamicType()) {
+ if (!type.IsMalformed() &&
+ (type.IsTypeParameter() || type.IsDynamicType())) {
// Replace the type with a malformed type and compile a throw when called.
redirection_type = ClassFinalizer::NewFinalizedMalformedType(
Error::Handle(), // No previous error.
@@ -2895,6 +2898,9 @@
current_member_ = &member;
if ((CurrentToken() == Token::kABSTRACT) &&
(LookaheadToken(1) != Token::kLPAREN)) {
+ if (FLAG_fail_legacy_abstract) {
+ ErrorMsg("illegal use of abstract");
+ }
ConsumeToken();
member.has_abstract = true;
}
@@ -3736,10 +3742,7 @@
// Map a malformed type argument to dynamic, so that malformed types with
// a resolved type class are handled properly in production mode.
if (type.IsMalformed()) {
- ASSERT(finalization != ClassFinalizer::kCanonicalizeWellFormed);
- if (finalization == ClassFinalizer::kCanonicalizeForCreation) {
- ErrorMsg(*malformed_error);
- }
+ ASSERT(finalization < ClassFinalizer::kCanonicalizeWellFormed);
type = Type::DynamicType();
}
types.Add(type);
@@ -5035,9 +5038,13 @@
// class in the current library (but not in its imports) and only create a new
// canonical signature class if it does not exist yet.
const String& signature = String::Handle(function.Signature());
- Class& signature_class = Class::ZoneHandle(
- library_.LookupLocalClass(signature));
-
+ Class& signature_class = Class::ZoneHandle();
+ if (!is_new_closure) {
+ signature_class = function.signature_class();
+ }
+ if (signature_class.IsNull()) {
+ signature_class = library_.LookupLocalClass(signature);
+ }
if (signature_class.IsNull()) {
// If we don't have a signature class yet, this must be a closure we
// have not parsed before.
@@ -6179,6 +6186,8 @@
catch_seen = true;
if (IsLiteral("on")) {
ConsumeToken();
+ // TODO(regis): The spec may change in the way a malformed 'on' type is
+ // treated. For now, we require the type to be wellformed.
exception_param.type = &AbstractType::ZoneHandle(
ParseType(ClassFinalizer::kCanonicalizeWellFormed));
} else {
@@ -6736,9 +6745,7 @@
bool Parser::IsLiteral(const char* literal) {
- const uint8_t* characters = reinterpret_cast<const uint8_t*>(literal);
- intptr_t len = strlen(literal);
- return IsIdentifier() && CurrentLiteral()->Equals(characters, len);
+ return IsIdentifier() && CurrentLiteral()->Equals(literal);
}
@@ -6837,8 +6844,8 @@
op_kind = Token::kISNOT;
}
const intptr_t type_pos = TokenPos();
- const AbstractType& type =
- AbstractType::ZoneHandle(ParseType(ClassFinalizer::kCanonicalize));
+ const AbstractType& type = AbstractType::ZoneHandle(
+ ParseType(ClassFinalizer::kCanonicalizeExpression));
if (!type.IsInstantiated() &&
(current_block_->scope->function_level() > 0)) {
// Make sure that the instantiator is captured.
@@ -7804,10 +7811,14 @@
}
// Resolve classname in the scope of the current library.
Error& error = Error::Handle();
- resolved_type_class =
- ResolveClassInCurrentLibraryScope(unresolved_class.token_pos(),
- unresolved_class_name,
- &error);
+ // If we finalize a type expression, as opposed to a type annotation, we
+ // tell the resolver (by passing NULL) to immediately report an ambiguous
+ // type as a compile time error.
+ resolved_type_class = ResolveClassInCurrentLibraryScope(
+ unresolved_class.token_pos(),
+ unresolved_class_name,
+ finalization >= ClassFinalizer::kCanonicalizeExpression ?
+ NULL : &error);
if (!error.IsNull()) {
*type = ClassFinalizer::NewFinalizedMalformedType(
error,
@@ -7823,11 +7834,15 @@
LibraryPrefix::Handle(unresolved_class.library_prefix());
// Resolve class name in the scope of the library prefix.
Error& error = Error::Handle();
- resolved_type_class =
- ResolveClassInPrefixScope(unresolved_class.token_pos(),
- lib_prefix,
- unresolved_class_name,
- &error);
+ // If we finalize a type expression, as opposed to a type annotation, we
+ // tell the resolver (by passing NULL) to immediately report an ambiguous
+ // type as a compile time error.
+ resolved_type_class = ResolveClassInPrefixScope(
+ unresolved_class.token_pos(),
+ lib_prefix,
+ unresolved_class_name,
+ finalization >= ClassFinalizer::kCanonicalizeExpression ?
+ NULL : &error);
if (!error.IsNull()) {
*type = ClassFinalizer::NewFinalizedMalformedType(
error,
@@ -8695,7 +8710,7 @@
}
ASSERT(type_arguments.IsNull() || (type_arguments.Length() == 1));
const Class& array_class = Class::Handle(
- Type::Handle(Type::ArrayType()).type_class());
+ Isolate::Current()->object_store()->array_class());
Type& type = Type::ZoneHandle(
Type::New(array_class, type_arguments, type_pos));
type ^= ClassFinalizer::FinalizeType(
@@ -8763,9 +8778,7 @@
return new LiteralNode(literal_pos, const_list);
} else {
// Factory call at runtime.
- // TODO(regis): Once _ListImpl is removed, use Symbols::List() instead of
- // Symbols::ListImplementation() on the following line.
- String& factory_class_name = String::Handle(Symbols::ListImplementation());
+ String& factory_class_name = String::Handle(Symbols::List());
const Class& factory_class =
Class::Handle(LookupCoreClass(factory_class_name));
ASSERT(!factory_class.IsNull());
@@ -9100,11 +9113,10 @@
}
intptr_t type_pos = TokenPos();
AbstractType& type = AbstractType::Handle(
- ParseType(ClassFinalizer::kCanonicalizeForCreation));
+ ParseType(ClassFinalizer::kCanonicalizeExpression));
// In case the type is malformed, throw a dynamic type error after finishing
// parsing the instance creation expression.
- if (type.IsTypeParameter() || type.IsDynamicType()) {
- ASSERT(!type.IsMalformed());
+ if (!type.IsMalformed() && (type.IsTypeParameter() || type.IsDynamicType())) {
// Replace the type with a malformed type.
type = ClassFinalizer::NewFinalizedMalformedType(
Error::Handle(), // No previous error.
diff --git a/runtime/vm/random.cc b/runtime/vm/random.cc
deleted file mode 100644
index ef2455c..0000000
--- a/runtime/vm/random.cc
+++ /dev/null
@@ -1,28 +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.
-
-#include "vm/random.h"
-
-#include "platform/assert.h"
-#include "vm/isolate.h"
-
-namespace dart {
-
-// LSFR step with a period of 31-bits.
-// Based on http://en.wikipedia.org/wiki/Linear_feedback_shift_register
-static int32_t LinearFeedbackShiftRegisterStep(int32_t seed) {
- return (seed >> 1) ^ ((-(seed & 1)) & (1 << 30 | 1 << 27));
-}
-
-
-int32_t Random::RandomInt32() {
- Isolate* isolate = Isolate::Current();
- ASSERT(isolate != NULL);
- int32_t result = isolate->random_seed();
- int32_t new_random_seed = LinearFeedbackShiftRegisterStep(result);
- isolate->set_random_seed(new_random_seed);
- return result;
-}
-
-} // namespace dart
diff --git a/runtime/vm/random.h b/runtime/vm/random.h
deleted file mode 100644
index ca1d039..0000000
--- a/runtime/vm/random.h
+++ /dev/null
@@ -1,23 +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 VM_RANDOM_H_
-#define VM_RANDOM_H_
-
-#include "vm/allocation.h"
-
-namespace dart {
-
-class Random : public AllStatic {
- public:
- static const int32_t kDefaultRandomSeed = 294967;
-
- // Generate a random number in the range [1, 2^31[ (will never return 0 or a
- // negative number). Not cryptographically safe.
- static int32_t RandomInt32();
-};
-
-} // namespace dart
-
-#endif // VM_RANDOM_H_
diff --git a/runtime/vm/random_test.cc b/runtime/vm/random_test.cc
deleted file mode 100644
index 2b7f726..0000000
--- a/runtime/vm/random_test.cc
+++ /dev/null
@@ -1,16 +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.
-
-#include "platform/assert.h"
-#include "vm/globals.h"
-#include "vm/random.h"
-#include "vm/unit_test.h"
-
-namespace dart {
-
-TEST_CASE(Random) {
- EXPECT(Random::RandomInt32() != 0);
-}
-
-} // namespace dart
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index a29c3ae..a99dde7 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -350,10 +350,9 @@
static bool IsByteArrayClassId(intptr_t index);
static bool IsExternalByteArrayClassId(intptr_t index);
- protected:
+ private:
uword tags_; // Various object tags (bits).
- private:
class FreeBit : public BitField<bool, kFreeBit, 1> {};
class MarkBit : public BitField<bool, kMarkBit, 1> {};
@@ -745,9 +744,9 @@
RawPcDescriptors* pc_descriptors_;
RawArray* deopt_info_array_;
RawArray* object_table_;
+ RawArray* static_calls_target_table_; // (code-offset, function, code).
RawArray* stackmaps_;
RawLocalVarDescriptors* var_descriptors_;
- RawGrowableObjectArray* resolved_static_calls_;
RawArray* comments_;
RawObject** to() {
return reinterpret_cast<RawObject**>(&ptr()->comments_);
@@ -1364,6 +1363,10 @@
return peer_;
}
+ static intptr_t data_offset() {
+ return OFFSET_OF(ExternalByteArrayData<T>, data_);
+ }
+
private:
T* data_;
void* peer_;
diff --git a/runtime/vm/scanner.cc b/runtime/vm/scanner.cc
index 229dfdf..26920c6 100644
--- a/runtime/vm/scanner.cc
+++ b/runtime/vm/scanner.cc
@@ -11,6 +11,7 @@
#include "vm/symbols.h"
#include "vm/thread.h"
#include "vm/token.h"
+#include "vm/unicode.h"
namespace dart {
@@ -174,6 +175,36 @@
}
+// This method is used when parsing integers and doubles in Dart code. We
+// are reusing the Scanner's handling of number literals in that situation.
+bool Scanner::IsValidLiteral(const Scanner::GrowableTokenStream& tokens,
+ Token::Kind literal_kind,
+ bool* is_positive,
+ String** value) {
+ if ((tokens.length() == 2) &&
+ (tokens[0].kind == literal_kind) &&
+ (tokens[1].kind == Token::kEOS)) {
+ *is_positive = true;
+ *value = tokens[0].literal;
+ return true;
+ }
+ if ((tokens.length() == 3) &&
+ ((tokens[0].kind == Token::kTIGHTADD) ||
+ (tokens[0].kind == Token::kSUB)) &&
+ (tokens[1].kind == literal_kind) &&
+ (tokens[2].kind == Token::kEOS)) {
+ // Check there is no space between "+/-" and number.
+ if ((tokens[0].offset + 1) != tokens[1].offset) {
+ return false;
+ }
+ *is_positive = tokens[0].kind == Token::kTIGHTADD;
+ *value = tokens[1].literal;
+ return true;
+ }
+ return false;
+}
+
+
void Scanner::ReadChar() {
if (lookahead_pos_ < source_length_) {
if (c0_ == '\n') {
@@ -438,7 +469,7 @@
}
-bool Scanner::ScanHexDigits(int digits, uint32_t* value) {
+bool Scanner::ScanHexDigits(int digits, int32_t* value) {
*value = 0;
for (int i = 0; i < digits; ++i) {
ReadChar();
@@ -453,7 +484,7 @@
}
-bool Scanner::ScanHexDigits(int min_digits, int max_digits, uint32_t* value) {
+bool Scanner::ScanHexDigits(int min_digits, int max_digits, int32_t* value) {
*value = 0;
ReadChar();
for (int i = 0; i < max_digits; ++i) {
@@ -472,7 +503,7 @@
}
-void Scanner::ScanEscapedCodePoint(uint32_t* code_point) {
+void Scanner::ScanEscapedCodePoint(int32_t* code_point) {
ASSERT(c0_ == 'u' || c0_ == 'x');
bool is_valid;
if (c0_ == 'x') {
@@ -498,7 +529,7 @@
void Scanner::ScanLiteralStringChars(bool is_raw) {
- GrowableArray<uint32_t> string_chars(64);
+ GrowableArray<int32_t> string_chars(64);
ASSERT(IsScanningString());
// We are at the first character of a string literal piece. A string literal
@@ -511,7 +542,7 @@
}
if (c0_ == '\\' && !is_raw) {
// Parse escape sequence.
- uint32_t escape_char = '\0';
+ int32_t escape_char = '\0';
ReadChar();
switch (c0_) {
case 'n':
@@ -852,8 +883,11 @@
ScanNumber(false);
} else {
char msg[128];
+ char utf8_char[5];
+ int len = Utf8::Encode(c0_, utf8_char);
+ utf8_char[len] = '\0';
OS::SNPrint(msg, sizeof(msg),
- "unexpected character: %c (%02x)\n", c0_, c0_);
+ "unexpected character: '%s' (U+%04X)\n", utf8_char, c0_);
ErrorMsg(msg);
ReadChar();
}
diff --git a/runtime/vm/scanner.h b/runtime/vm/scanner.h
index 5700475..5f1f75e 100644
--- a/runtime/vm/scanner.h
+++ b/runtime/vm/scanner.h
@@ -96,6 +96,13 @@
// Return true if str is an identifier.
static bool IsIdent(const String& str);
+ // Does the token stream contain a valid literal. This is used to implement
+ // the Dart methods int.parse and double.parse.
+ static bool IsValidLiteral(const Scanner::GrowableTokenStream& tokens,
+ Token::Kind literal_kind,
+ bool* is_positive,
+ String** value);
+
private:
struct ScanContext {
ScanContext* next;
@@ -171,13 +178,13 @@
void ScanLiteralStringChars(bool is_raw);
// Reads a fixed number of hexadecimal digits.
- bool ScanHexDigits(int digits, uint32_t* value);
+ bool ScanHexDigits(int digits, int32_t* value);
// Reads a variable number of hexadecimal digits.
- bool ScanHexDigits(int min_digits, int max_digits, uint32_t* value);
+ bool ScanHexDigits(int min_digits, int max_digits, int32_t* value);
// Reads an escaped code point from within a string literal.
- void ScanEscapedCodePoint(uint32_t* escaped_char);
+ void ScanEscapedCodePoint(int32_t* escaped_char);
// Reads identifier.
RawString* ConsumeIdentChars(bool allow_dollar);
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index c11e321..044d34b 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -818,7 +818,7 @@
if (class_id >= kNumPredefinedCids) {
if (Class::IsSignatureClass(cls)) {
// We do not allow closure objects in an isolate message.
- set_exception_type(Exceptions::kArgumentError);
+ set_exception_type(Exceptions::kArgument);
// TODO(6726): Allocate these constant strings once in the VM isolate.
set_exception_msg("Illegal argument in isolate message"
" : (object is a closure)");
@@ -1073,7 +1073,7 @@
if (class_id >= kNumPredefinedCids) {
if (Class::IsSignatureClass(cls)) {
// We do not allow closure objects in an isolate message.
- set_exception_type(Exceptions::kArgumentError);
+ set_exception_type(Exceptions::kArgument);
// TODO(6726): Allocate these constant strings once in the VM isolate.
set_exception_msg("Illegal argument in isolate message"
" : (object is a closure)");
@@ -1081,7 +1081,7 @@
}
if (cls->ptr()->num_native_fields_ != 0) {
// We do not allow objects with native fields in an isolate message.
- set_exception_type(Exceptions::kArgumentError);
+ set_exception_type(Exceptions::kArgument);
// TODO(6726): Allocate these constant strings once in the VM isolate.
set_exception_msg("Illegal argument in isolate message"
" : (object extends NativeWrapper)");
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index 083b28f..07326ae 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -528,13 +528,13 @@
TEST_CASE(SerializeString) {
TestString("This string shall be serialized");
TestString("æøå"); // This file is UTF-8 encoded.
- char data[] = {0x01,
- 0x7f,
- 0xc2, 0x80, // 0x80
- 0xdf, 0xbf, // 0x7ff
- 0xe0, 0xa0, 0x80, // 0x800
- 0xef, 0xbf, 0xbf, // 0xffff
- 0x00}; // String termination.
+ const char* data = "\x01"
+ "\x7F"
+ "\xC2\x80" // U+0080
+ "\xDF\xBF" // U+07FF
+ "\xE0\xA0\x80" // U+0800
+ "\xEF\xBF\xBF"; // U+FFFF
+
TestString(data);
// TODO(sgjesse): Add tests with non-BMP characters.
}
@@ -1030,7 +1030,7 @@
UNIT_TEST_CASE(ScriptSnapshot) {
const char* kLibScriptChars =
- "#library('dart:import-lib');"
+ "library dart_import_lib;"
"class LibFields {"
" LibFields(int i, int j) : fld1 = i, fld2 = j {}"
" int fld1;"
@@ -1095,7 +1095,7 @@
Dart_EnterScope(); // Start a Dart API scope for invoking API functions.
// Load the library.
- Dart_Handle import_lib = Dart_LoadLibrary(NewString("dart:import-lib"),
+ Dart_Handle import_lib = Dart_LoadLibrary(NewString("dart_import_lib"),
NewString(kLibScriptChars));
EXPECT_VALID(import_lib);
@@ -1701,7 +1701,7 @@
UNIT_TEST_CASE(DartGeneratedListMessagesWithBackref) {
const int kArrayLength = 10;
static const char* kScriptChars =
- "#import('dart:scalarlist');\n"
+ "import 'dart:scalarlist';\n"
"final int kArrayLength = 10;\n"
"getStringList() {\n"
" var s = 'Hello, world!';\n"
@@ -1872,7 +1872,7 @@
UNIT_TEST_CASE(DartGeneratedArrayLiteralMessagesWithBackref) {
const int kArrayLength = 10;
static const char* kScriptChars =
- "#import('dart:scalarlist');\n"
+ "import 'dart:scalarlist';\n"
"final int kArrayLength = 10;\n"
"getStringList() {\n"
" var s = 'Hello, world!';\n"
@@ -1911,7 +1911,7 @@
"getMixedList() {\n"
" var list = [];\n"
" for (var i = 0; i < kArrayLength; i++) {\n"
- " list.add(((i % 2) == 0) ? 'A' : 2.72);\n"
+ " list.add(((i % 2) == 0) ? '.' : 2.72);\n"
" }\n"
" return list;\n"
"}\n"
@@ -2017,7 +2017,7 @@
if ((i % 2) == 0) {
EXPECT_EQ(root->value.as_array.values[0], element);
EXPECT_EQ(Dart_CObject::kString, element->type);
- EXPECT_STREQ("A", element->value.as_string);
+ EXPECT_STREQ(".", element->value.as_string);
} else {
EXPECT_EQ(root->value.as_array.values[1], element);
EXPECT_EQ(Dart_CObject::kDouble, element->type);
@@ -2048,7 +2048,7 @@
// Create a native port for posting from C to Dart
TestIsolateScope __test_isolate__;
const char* kScriptChars =
- "#import('dart:isolate');\n"
+ "import 'dart:isolate';\n"
"main() {\n"
" var messageCount = 0;\n"
" var exception = '';\n"
@@ -2107,7 +2107,7 @@
EXPECT(Dart_PostCObject(send_port_id, &object));
// Try to post an invalid UTF-8 sequence (lead surrogate).
- char data[] = {0xed, 0xa0, 0x80, 0}; // 0xd800
+ const char* data = "\xED\xA0\x80"; // U+D800
object.type = Dart_CObject::kString;
object.value.as_string = const_cast<char*>(data);
EXPECT(!Dart_PostCObject(send_port_id, &object));
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index 79badc1..f354cab 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -183,48 +183,19 @@
// Input parameters:
-// ECX: function object.
// EDX: arguments descriptor array (num_args is first Smi element).
void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) {
const Immediate raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
-
- __ movl(EAX, FieldAddress(ECX, Function::code_offset()));
- __ cmpl(EAX, raw_null);
- Label function_compiled;
- __ j(NOT_EQUAL, &function_compiled, Assembler::kNearJump);
-
- // Create a stub frame as we are pushing some objects on the stack before
- // calling into the runtime.
AssemblerMacros::EnterStubFrame(assembler);
-
__ pushl(EDX); // Preserve arguments descriptor array.
- __ pushl(ECX);
- __ CallRuntime(kCompileFunctionRuntimeEntry);
- __ popl(ECX); // Restore read-only function object argument in ECX.
- __ popl(EDX); // Restore arguments descriptor array.
- // Restore EAX.
- __ movl(EAX, FieldAddress(ECX, Function::code_offset()));
-
- // Remove the stub frame as we are about to jump to the dart function.
- __ LeaveFrame();
-
- __ Bind(&function_compiled);
- // Patch caller.
-
- // Create a stub frame as we are pushing some objects on the stack before
- // calling into the runtime.
- AssemblerMacros::EnterStubFrame(assembler);
-
- __ pushl(EDX); // Preserve arguments descriptor array.
- __ pushl(ECX); // Preserve function object.
+ __ pushl(raw_null); // Setup space on stack for return value.
__ CallRuntime(kPatchStaticCallRuntimeEntry);
- __ popl(ECX); // Restore function object argument in ECX.
+ __ popl(EAX); // Get Code object result.
__ popl(EDX); // Restore arguments descriptor array.
// Remove the stub frame as we are about to jump to the dart function.
__ LeaveFrame();
- __ movl(EAX, FieldAddress(ECX, Function::code_offset()));
__ movl(ECX, FieldAddress(EAX, Code::instructions_offset()));
__ addl(ECX, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
__ jmp(ECX);
@@ -233,20 +204,18 @@
// Called from a static call only when an invalid code has been entered
// (invalid because its function was optimized or deoptimized).
-// ECX: function object.
// EDX: arguments descriptor array (num_args is first Smi element).
void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) {
+ const Immediate raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
// Create a stub frame as we are pushing some objects on the stack before
// calling into the runtime.
AssemblerMacros::EnterStubFrame(assembler);
__ pushl(EDX); // Preserve arguments descriptor array.
- __ pushl(ECX); // Preserve target function.
- __ pushl(ECX); // Target function.
+ __ pushl(raw_null); // Setup space on stack for return value.
__ CallRuntime(kFixCallersTargetRuntimeEntry);
- __ popl(EAX); // discard argument.
- __ popl(EAX); // Restore function.
+ __ popl(EAX); // Get Code object.
__ popl(EDX); // Restore arguments descriptor array.
- __ movl(EAX, FieldAddress(EAX, Function::code_offset()));
__ movl(EAX, FieldAddress(EAX, Code::instructions_offset()));
__ addl(EAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
__ LeaveFrame();
@@ -1816,23 +1785,23 @@
}
-// ECX: Function object.
// EDX: Arguments array.
// TOS(0): return address (Dart code).
void StubCode::GenerateBreakpointStaticStub(Assembler* assembler) {
// Create a stub frame as we are pushing some objects on the stack before
// calling into the runtime.
AssemblerMacros::EnterStubFrame(assembler);
- __ pushl(EDX);
- __ pushl(ECX);
+ __ pushl(EDX); // Preserve arguments descriptor.
+ const Immediate raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+ __ pushl(raw_null); // Room for result.
__ CallRuntime(kBreakpointStaticHandlerRuntimeEntry);
- __ popl(ECX);
- __ popl(EDX);
+ __ popl(EAX); // Code object.
+ __ popl(EDX); // Restore arguments descriptor.
__ LeaveFrame();
// Now call the static function. The breakpoint handler function
// ensures that the call target is compiled.
- __ movl(EAX, FieldAddress(ECX, Function::code_offset()));
__ movl(ECX, FieldAddress(EAX, Code::instructions_offset()));
__ addl(ECX, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
__ jmp(ECX);
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index 5048aa5..65ea307 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -182,44 +182,18 @@
// Input parameters:
-// RBX: function object.
// R10: arguments descriptor array (num_args is first Smi element).
void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) {
const Immediate raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
-
- __ movq(RAX, FieldAddress(RBX, Function::code_offset()));
- __ cmpq(RAX, raw_null);
- Label function_compiled;
- __ j(NOT_EQUAL, &function_compiled, Assembler::kNearJump);
-
- // Create a stub frame as we are pushing some objects on the stack before
- // calling into the runtime.
AssemblerMacros::EnterStubFrame(assembler);
-
__ pushq(R10); // Preserve arguments descriptor array.
- __ pushq(RBX);
- __ CallRuntime(kCompileFunctionRuntimeEntry);
- __ popq(RBX); // Restore read-only function object argument in RBX.
- __ popq(R10); // Restore arguments descriptor array.
- // Restore RAX.
- __ movq(RAX, FieldAddress(RBX, Function::code_offset()));
-
- // Remove the stub frame as we are about to jump to the dart function.
- __ LeaveFrame();
-
- __ Bind(&function_compiled);
- // Patch caller.
- AssemblerMacros::EnterStubFrame(assembler);
-
- __ pushq(R10); // Preserve arguments descriptor array.
- __ pushq(RBX); // Preserve function object.
+ __ pushq(raw_null); // Setup space on stack for return value.
__ CallRuntime(kPatchStaticCallRuntimeEntry);
- __ popq(RBX); // Restore function object argument in RBX.
+ __ popq(RAX); // Get Code object result.
__ popq(R10); // Restore arguments descriptor array.
// Remove the stub frame as we are about to jump to the dart function.
__ LeaveFrame();
- __ movq(RAX, FieldAddress(RBX, Function::code_offset()));
__ movq(RBX, FieldAddress(RAX, Code::instructions_offset()));
__ addq(RBX, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
@@ -229,18 +203,16 @@
// Called from a static call only when an invalid code has been entered
// (invalid because its function was optimized or deoptimized).
-// RBX: function object.
// R10: arguments descriptor array (num_args is first Smi element).
void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) {
+ const Immediate raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
AssemblerMacros::EnterStubFrame(assembler);
__ pushq(R10); // Preserve arguments descriptor array.
- __ pushq(RBX); // Preserve target function.
- __ pushq(RBX); // Target function.
+ __ pushq(raw_null); // Setup space on stack for return value.
__ CallRuntime(kFixCallersTargetRuntimeEntry);
- __ popq(RAX); // discard argument.
- __ popq(RAX); // Restore function.
+ __ popq(RAX); // Get Code object.
__ popq(R10); // Restore arguments descriptor array.
- __ movq(RAX, FieldAddress(RAX, Function::code_offset()));
__ movq(RAX, FieldAddress(RAX, Code::instructions_offset()));
__ addq(RAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
__ LeaveFrame();
@@ -1787,21 +1759,21 @@
GenerateNArgsCheckInlineCacheStub(assembler, 1);
}
-// RBX: Function object.
// R10: Arguments array.
// TOS(0): return address (Dart code).
void StubCode::GenerateBreakpointStaticStub(Assembler* assembler) {
+ const Immediate raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
AssemblerMacros::EnterStubFrame(assembler);
- __ pushq(R10);
- __ pushq(RBX);
+ __ pushq(R10); // Preserve arguments descriptor.
+ __ pushq(raw_null); // Room for result.
__ CallRuntime(kBreakpointStaticHandlerRuntimeEntry);
- __ popq(RBX);
- __ popq(R10);
+ __ popq(RAX); // Code object.
+ __ popq(R10); // Restore arguments descriptor.
__ LeaveFrame();
// Now call the static function. The breakpoint handler function
// ensures that the call target is compiled.
- __ movq(RAX, FieldAddress(RBX, Function::code_offset()));
__ movq(RBX, FieldAddress(RAX, Code::instructions_offset()));
__ addq(RBX, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
__ jmp(RBX);
diff --git a/runtime/vm/symbols.cc b/runtime/vm/symbols.cc
index 33c0ac6..c7da37c 100644
--- a/runtime/vm/symbols.cc
+++ b/runtime/vm/symbols.cc
@@ -26,8 +26,8 @@
};
-const char* Symbols::Name(intptr_t symbol) {
- ASSERT((symbol > kIllegal) && (symbol < kMaxId));
+const char* Symbols::Name(SymbolId symbol) {
+ ASSERT((symbol > kIllegal) && (symbol < kMaxPredefinedId));
return names[symbol];
}
@@ -40,12 +40,12 @@
SetupSymbolTable(isolate);
// Create all predefined symbols.
- ASSERT((sizeof(names) / sizeof(const char*)) == Symbols::kMaxId);
+ ASSERT((sizeof(names) / sizeof(const char*)) == Symbols::kMaxPredefinedId);
ObjectStore* object_store = isolate->object_store();
Array& symbol_table = Array::Handle();
dart::String& str = String::Handle();
- for (intptr_t i = 1; i < Symbols::kMaxId; i++) {
+ for (intptr_t i = 1; i < Symbols::kMaxPredefinedId; i++) {
// The symbol_table needs to be reloaded as it might have grown in the
// previous iteration.
symbol_table = object_store->symbol_table();
@@ -54,6 +54,11 @@
predefined_[i] = str.raw();
}
Object::RegisterSingletonClassNames();
+
+ for (int32_t c = 0; c <= kMaxOneCharCodeSymbol; c++) {
+ ASSERT(kMaxPredefinedId + c < kMaxId);
+ predefined_[kMaxPredefinedId + c] = New(&c, 1);
+ }
}
@@ -107,7 +112,7 @@
Utf8::DecodeToLatin1(utf8_array, str_len, characters, len);
return New(characters, len);
}
- ASSERT((type == Utf8::kBMP) || (type == Utf8::kSMP));
+ ASSERT((type == Utf8::kBMP) || (type == Utf8::kSupplementary));
uint16_t* characters = zone->Alloc<uint16_t>(len);
Utf8::DecodeToUTF16(utf8_array, str_len, characters, len);
return New(characters, len);
@@ -117,7 +122,6 @@
template<typename T>
RawString* Symbols::New(const T* characters, intptr_t len) {
Isolate* isolate = Isolate::Current();
- ASSERT(isolate != Dart::vm_isolate());
String& symbol = String::Handle(isolate, String::null());
Array& symbol_table = Array::Handle(isolate, Array::null());
@@ -148,7 +152,7 @@
template RawString* Symbols::New(const uint8_t* characters, intptr_t len);
template RawString* Symbols::New(const uint16_t* characters, intptr_t len);
-template RawString* Symbols::New(const uint32_t* characters, intptr_t len);
+template RawString* Symbols::New(const int32_t* characters, intptr_t len);
RawString* Symbols::New(const String& str) {
@@ -200,6 +204,14 @@
}
+RawString* Symbols::FromCharCode(int32_t char_code) {
+ if (char_code > kMaxOneCharCodeSymbol) {
+ return New(&char_code, 1);
+ }
+ return predefined_[kNullCharId + char_code];
+}
+
+
void Symbols::GrowSymbolTable(const Array& symbol_table) {
// TODO(iposva): Avoid exponential growth.
intptr_t table_size = symbol_table.Length() - 1;
@@ -277,7 +289,7 @@
intptr_t len,
intptr_t hash);
template intptr_t Symbols::FindIndex(const Array& symbol_table,
- const uint32_t* characters,
+ const int32_t* characters,
intptr_t len,
intptr_t hash);
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 16c1fd4..0e6cc21 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -42,8 +42,8 @@
"AbstractClassInstantiationErrorImplementation") \
V(NoSuchMethodError, "NoSuchMethodErrorImplementation") \
V(ThrowNew, "_throwNew") \
+ V(List, "List") \
V(ListLiteralFactory, "List._fromLiteral") \
- V(ListImplementation, "_ListImpl") \
V(ListFactory, "List.") \
V(MapImplementation, "_HashMapImpl") \
V(MapLiteralFactory, "Map._fromLiteral") \
@@ -146,16 +146,19 @@
// without having to maintain copies in each isolate.
class Symbols : public AllStatic {
public:
+ enum { kMaxOneCharCodeSymbol = 0xFF };
+
// List of strings that are pre created in the vm isolate.
- enum {
+ enum SymbolId {
kIllegal = 0,
#define DEFINE_SYMBOL_INDEX(symbol, literal) \
k##symbol,
PREDEFINED_SYMBOLS_LIST(DEFINE_SYMBOL_INDEX)
#undef DEFINE_SYMBOL_INDEX
-
- kMaxId,
+ kMaxPredefinedId,
+ kNullCharId = kMaxPredefinedId,
+ kMaxId = kNullCharId + kMaxOneCharCodeSymbol + 1,
};
// Access methods for symbols stored in the vm isolate.
@@ -183,11 +186,17 @@
intptr_t length);
// Returns char* of predefined symbol.
- static const char* Name(intptr_t symbol);
+ static const char* Name(SymbolId symbol);
+
+ static RawString* FromCharCode(int32_t char_code);
+
+ static RawString** PredefinedAddress() {
+ return reinterpret_cast<RawString**>(&predefined_);
+ }
private:
enum {
- kInitialVMIsolateSymtabSize = ((Symbols::kMaxId + 15) & -16),
+ kInitialVMIsolateSymtabSize = ((kMaxId + 15) & -16),
kInitialSymtabSize = 256
};
@@ -218,11 +227,11 @@
static RawObject* GetVMSymbol(intptr_t object_id);
static bool IsVMSymbolId(intptr_t object_id) {
return (object_id >= kMaxPredefinedObjectIds &&
- object_id < (kMaxPredefinedObjectIds + Symbols::kMaxId));
+ object_id < (kMaxPredefinedObjectIds + kMaxId));
}
// List of symbols that are stored in the vm isolate for easy access.
- static RawString* predefined_[Symbols::kMaxId];
+ static RawString* predefined_[kMaxId];
friend class SnapshotReader;
friend class SnapshotWriter;
diff --git a/runtime/vm/unicode.cc b/runtime/vm/unicode.cc
index e2e741d8..3129a06 100644
--- a/runtime/vm/unicode.cc
+++ b/runtime/vm/unicode.cc
@@ -64,18 +64,12 @@
}
-static bool IsSmpSequenceStart(uint8_t code_unit) {
+static bool IsSupplementarySequenceStart(uint8_t code_unit) {
// Check is codepoint is >= U+10000.
return (code_unit >= 0xF0);
}
-// Returns true if the code point is a high- or low-surrogate.
-static bool IsSurrogate(uint32_t code_point) {
- return (code_point & 0xfffff800) == 0xd800;
-}
-
-
// Returns true if the code point value is above Plane 17.
static bool IsOutOfRange(uint32_t code_point) {
return (code_point > 0x10FFFF);
@@ -88,14 +82,6 @@
}
-void Utf8::ConvertUTF32ToUTF16(int32_t codepoint, uint16_t* dst) {
- ASSERT(codepoint > kMaxBmpCodepoint);
- ASSERT(dst != NULL);
- dst[0] = (Utf8::kLeadOffset + (codepoint >> 10));
- dst[1] = (0xDC00 + (codepoint & 0x3FF));
-}
-
-
// Returns a count of the number of UTF-8 trail bytes.
intptr_t Utf8::CodePointCount(const uint8_t* utf8_array,
intptr_t array_len,
@@ -108,8 +94,8 @@
++len;
}
if (!IsLatin1SequenceStart(code_unit)) { // > U+00FF
- if (IsSmpSequenceStart(code_unit)) { // >= U+10000
- char_type = kSMP;
+ if (IsSupplementarySequenceStart(code_unit)) { // >= U+10000
+ char_type = kSupplementary;
++len;
} else if (char_type == kLatin1) {
char_type = kBMP;
@@ -144,7 +130,7 @@
(j == num_trail_bytes) &&
!IsOutOfRange(ch) &&
!IsNonShortestForm(ch, j) &&
- !IsSurrogate(ch))) {
+ !Utf16::IsSurrogate(ch))) {
return false;
}
}
@@ -169,8 +155,9 @@
intptr_t Utf8::Length(const String& str) {
intptr_t length = 0;
- for (intptr_t i = 0; i < str.Length(); ++i) {
- int32_t ch = str.CharAt(i);
+ String::CodePointIterator it(str);
+ while (it.Next()) {
+ int32_t ch = it.Current();
length += Utf8::Length(ch);
}
return length;
@@ -205,8 +192,9 @@
intptr_t Utf8::Encode(const String& src, char* dst, intptr_t len) {
intptr_t pos = 0;
- for (intptr_t i = 0; i < src.Length(); ++i) {
- intptr_t ch = src.CharAt(i);
+ String::CodePointIterator it(src);
+ while (it.Next()) {
+ int32_t ch = it.Current();
intptr_t num_bytes = Utf8::Length(ch);
if (pos + num_bytes > len) {
break;
@@ -224,7 +212,7 @@
uint32_t ch = utf8_array[0] & 0xFF;
intptr_t i = 1;
if (ch >= 0x80) {
- int32_t num_trail_bytes = kTrailBytes[ch];
+ intptr_t num_trail_bytes = kTrailBytes[ch];
bool is_malformed = false;
for (; i < num_trail_bytes; ++i) {
if (i < array_len) {
@@ -241,7 +229,7 @@
(i == num_trail_bytes) &&
!IsOutOfRange(ch) &&
!IsNonShortestForm(ch, i) &&
- !IsSurrogate(ch))) {
+ !Utf16::IsSurrogate(ch))) {
*dst = -1;
return 0;
}
@@ -284,13 +272,13 @@
intptr_t num_bytes;
for (; (i < array_len) && (j < len); i += num_bytes, ++j) {
int32_t ch;
- bool is_smp = IsSmpSequenceStart(utf8_array[i]);
+ bool is_supplementary = IsSupplementarySequenceStart(utf8_array[i]);
num_bytes = Utf8::Decode(&utf8_array[i], (array_len - i), &ch);
if (ch == -1) {
return false; // invalid input
}
- if (is_smp) {
- ConvertUTF32ToUTF16(ch, &(dst[j]));
+ if (is_supplementary) {
+ Utf16::Encode(ch, &dst[j]);
j = j + 1;
} else {
dst[j] = ch;
@@ -305,7 +293,7 @@
bool Utf8::DecodeToUTF32(const uint8_t* utf8_array,
intptr_t array_len,
- uint32_t* dst,
+ int32_t* dst,
intptr_t len) {
intptr_t i = 0;
intptr_t j = 0;
@@ -324,4 +312,12 @@
return true; // success
}
+
+void Utf16::Encode(int32_t codepoint, uint16_t* dst) {
+ ASSERT(codepoint > kMaxBmpCodepoint);
+ ASSERT(dst != NULL);
+ dst[0] = (Utf16::kLeadSurrogateOffset + (codepoint >> 10));
+ dst[1] = (0xDC00 + (codepoint & 0x3FF));
+}
+
} // namespace dart
diff --git a/runtime/vm/unicode.h b/runtime/vm/unicode.h
index 28beaad..03a4b29 100644
--- a/runtime/vm/unicode.h
+++ b/runtime/vm/unicode.h
@@ -15,20 +15,16 @@
class Utf8 : AllStatic {
public:
enum Type {
- kLatin1 = 0, // Latin-1 character set.
- kBMP, // Basic Multilingual Plane.
- kSMP, // Supplementary Multilingual Plane.
+ kLatin1 = 0, // Latin-1 code point [U+0000, U+00FF].
+ kBMP, // Basic Multilingual Plane code point [U+0000, U+FFFF].
+ kSupplementary, // Supplementary code point [U+010000, U+10FFFF].
};
static const intptr_t kMaxOneByteChar = 0x7F;
static const intptr_t kMaxTwoByteChar = 0x7FF;
static const intptr_t kMaxThreeByteChar = 0xFFFF;
static const intptr_t kMaxFourByteChar = 0x10FFFF;
- static const intptr_t kMaxBmpCodepoint = 0xffff;
- static const int32_t kLeadOffset = (0xD800 - (0x10000 >> 10));
- static const int32_t kSurrogateOffset = (0x10000 - (0xD800 << 10) - 0xDC00);
- static void ConvertUTF32ToUTF16(int32_t codepoint, uint16_t* dst);
static intptr_t CodePointCount(const uint8_t* utf8_array,
intptr_t array_len,
Type* type);
@@ -56,10 +52,10 @@
intptr_t len);
static bool DecodeToUTF32(const uint8_t* utf8_array,
intptr_t array_len,
- uint32_t* dst,
+ int32_t* dst,
intptr_t len);
static bool DecodeCStringToUTF32(const char* str,
- uint32_t* dst,
+ int32_t* dst,
intptr_t len) {
ASSERT(str != NULL);
intptr_t array_len = strlen(str);
@@ -69,6 +65,44 @@
};
+class Utf16 : AllStatic {
+ public:
+ static const int32_t kMaxBmpCodepoint = 0xFFFF;
+
+ static const int32_t kLeadSurrogateOffset = (0xD800 - (0x10000 >> 10));
+
+ static const int32_t kSurrogateOffset = (0x10000 - (0xD800 << 10) - 0xDC00);
+
+ // Returns the length of the code point in UTF-16 code units.
+ static intptr_t Length(int32_t ch) {
+ return (ch <= kMaxBmpCodepoint) ? 1 : 2;
+ }
+
+ // Returns true if ch is a lead or trail surrogate.
+ static bool IsSurrogate(int32_t ch) {
+ return (ch & 0xFFFFF800) == 0xD800;
+ }
+
+ // Returns true if ch is a lead surrogate.
+ static bool IsLeadSurrogate(int32_t ch) {
+ return (ch & 0xFFFFFC00) == 0xD800;
+ }
+
+ // Returns true if ch is a low surrogate.
+ static bool IsTrailSurrogate(int32_t ch) {
+ return (ch & 0xFFFFFC00) == 0xDC00;
+ }
+
+ // Decodes a surrogate pair into a supplementary code point.
+ static int32_t Decode(int32_t lead, int32_t trail) {
+ return 0x10000 + ((lead & 0x3FF) << 10) + (trail & 0x3FF);
+ }
+
+ // Encodes a single code point.
+ static void Encode(int32_t codepoint, uint16_t* dst);
+};
+
+
class CaseMapping : AllStatic {
public:
// Maps a code point to uppercase.
diff --git a/runtime/vm/unicode_test.cc b/runtime/vm/unicode_test.cc
index 967e9ca..582a2a6 100644
--- a/runtime/vm/unicode_test.cc
+++ b/runtime/vm/unicode_test.cc
@@ -12,8 +12,8 @@
// Examples from the Unicode specification, chapter 3
{
const char* src = "\x41\xC3\xB1\x42";
- uint32_t expected[] = { 0x41, 0xF1, 0x42 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x41, 0xF1, 0x42 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(is_valid);
@@ -22,8 +22,8 @@
{
const char* src = "\x4D";
- uint32_t expected[] = { 0x4D };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x4D };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(is_valid);
@@ -32,8 +32,8 @@
{
const char* src = "\xD0\xB0";
- uint32_t expected[] = { 0x430 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x430 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(is_valid);
@@ -42,8 +42,8 @@
{
const char* src = "\xE4\xBA\x8C";
- uint32_t expected[] = { 0x4E8C };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x4E8C };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(is_valid);
@@ -52,8 +52,8 @@
{
const char* src = "\xF0\x90\x8C\x82";
- uint32_t expected[] = { 0x10302 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x10302 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(is_valid);
@@ -62,8 +62,8 @@
{
const char* src = "\x4D\xD0\xB0\xE4\xBA\x8C\xF0\x90\x8C\x82";
- uint32_t expected[] = { 0x4D, 0x430, 0x4E8C, 0x10302 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x4D, 0x430, 0x4E8C, 0x10302 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(is_valid);
@@ -75,10 +75,10 @@
const char* src = "\xD7\x92\xD7\x9C\xD7\xA2\xD7\x93"
"\x20"
"\xD7\x91\xD7\xA8\xD7\x9B\xD7\x94";
- uint32_t expected[] = { 0x5D2, 0x5DC, 0x5E2, 0x5D3,
- 0x20,
- 0x5D1, 0x5E8, 0x5DB, 0x5D4 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x5D2, 0x5DC, 0x5E2, 0x5D3,
+ 0x20,
+ 0x5D1, 0x5E8, 0x5DB, 0x5D4 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(is_valid);
@@ -90,8 +90,8 @@
// 1 - Some correct UTF-8 text
{
const char* src = "\xCE\xBA\xE1\xBD\xB9\xCF\x83\xCE\xBC\xCE\xB5";
- uint32_t expected[] = { 0x3BA, 0x1F79, 0x3C3, 0x3BC, 0x3B5 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x3BA, 0x1F79, 0x3C3, 0x3BC, 0x3B5 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(is_valid);
@@ -105,8 +105,8 @@
// 2.1.1 - 1 byte (U-00000000): "\x00"
{
const char* src = "\x00";
- uint32_t expected[] = { 0x0 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x0 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0xFF, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(is_valid);
@@ -116,8 +116,8 @@
// 2.1.2 - 2 bytes (U-00000080): "\xC2\x80"
{
const char* src = "\xC2\x80";
- uint32_t expected[] = { 0x80 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x80 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(is_valid);
@@ -127,8 +127,8 @@
// 2.1.3 - 3 bytes (U-00000800): "\xE0\xA0\x80"
{
const char* src = "\xE0\xA0\x80";
- uint32_t expected[] = { 0x800 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x800 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(is_valid);
@@ -138,8 +138,8 @@
// 2.1.4 - 4 bytes (U-00010000): "\xF0\x90\x80\x80"
{
const char* src = "\xF0\x90\x80\x80";
- uint32_t expected[] = { 0x10000 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x10000 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(is_valid);
@@ -149,8 +149,8 @@
// 2.1.5 - 5 bytes (U-00200000): "\xF8\x88\x80\x80\x80"
{
const char* src = "\xF8\x88\x80\x80\x80";
- uint32_t expected[] = { 0x200000 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x200000 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -160,8 +160,8 @@
// 2.1.6 - 6 bytes (U-04000000): "\xFC\x84\x80\x80\x80\x80"
{
const char* src = "\xFC\x84\x80\x80\x80\x80";
- uint32_t expected[] = { 0x400000 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x400000 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -173,8 +173,8 @@
// 2.2.1 - 1 byte (U-0000007F): "\x7F"
{
const char* src = "\x7F";
- uint32_t expected[] = { 0x7F };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x7F };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(is_valid);
@@ -184,8 +184,8 @@
// 2.2.2 - 2 bytes (U-000007FF): "\xDF\xBF"
{
const char* src = "\xDF\xBF";
- uint32_t expected[] = { 0x7FF };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x7FF };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(is_valid);
@@ -195,8 +195,8 @@
// 2.2.3 - 3 bytes (U-0000FFFF): "\xEF\xBF\xBF"
{
const char* src = "\xEF\xBF\xBF";
- uint32_t expected[] = { 0xFFFF };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xFFFF };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(is_valid);
@@ -206,8 +206,8 @@
// 2.2.4 - 4 bytes (U-001FFFFF): "\xF7\xBF\xBF\xBF"
{
const char* src = "\xF7\xBF\xBF\xBF";
- uint32_t expected[] = { 0x1FFFF };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x1FFFF };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -217,8 +217,8 @@
// 2.2.5 - 5 bytes (U-03FFFFFF): "\xFB\xBF\xBF\xBF\xBF"
{
const char* src = "\xFB\xBF\xBF\xBF\xBF";
- uint32_t expected[] = { 0x3FFFFFF };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x3FFFFFF };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -228,8 +228,8 @@
// 2.2.6 - 6 bytes (U-7FFFFFFF): "\xFD\xBF\xBF\xBF\xBF\xBF"
{
const char* src = "\xFD\xBF\xBF\xBF\xBF\xBF";
- uint32_t expected[] = { 0x7FFFFFF };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x7FFFFFF };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -241,8 +241,8 @@
// 2.3.1 - U-0000D7FF = ed 9f bf = "\xED\x9F\xBF"
{
const char* src = "\xED\x9F\xBF";
- uint32_t expected[] = { 0xD7FF };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xD7FF };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(is_valid);
@@ -252,8 +252,8 @@
// 2.3.2 - U-0000E000 = ee 80 80 = "\xEE\x80\x80"
{
const char* src = "\xEE\x80\x80";
- uint32_t expected[] = { 0xE000 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xE000 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(is_valid);
@@ -263,8 +263,8 @@
// 2.3.3 - U-0000FFFD = ef bf bd = "\xEF\xBF\xBD"
{
const char* src = "\xEF\xBF\xBD";
- uint32_t expected[] = { 0xFFFD };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xFFFD };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(is_valid);
@@ -274,8 +274,8 @@
// 2.3.4 - U-0010FFFF = f4 8f bf bf = "\xF4\x8F\xBF\xBF"
{
const char* src = "\xF4\x8F\xBF\xBF";
- uint32_t expected[] = { 0x10FFFF };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x10FFFF };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(is_valid);
@@ -285,8 +285,8 @@
// 2.3.5 - U-00110000 = f4 90 80 80 = "\xF4\x90\x80\x80"
{
const char* src = "\xF4\x90\x80\x80";
- uint32_t expected[] = { 0x110000 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x110000 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -300,8 +300,8 @@
// 3.1.1 - First continuation byte 0x80: "\x80"
{
const char* src = "\x80";
- uint32_t expected[] = { 0x80 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x80 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -311,8 +311,8 @@
// 3.1.2 - Last continuation byte 0xbf: "\xBF"
{
const char* src = "\xBF";
- uint32_t expected[] = { 0xBF };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xBF };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -322,8 +322,8 @@
// 3.1.3 - 2 continuation bytes: "\x80\xBF"
{
const char* src = "\x80\xBF";
- uint32_t expected[] = { 0x80, 0xBF };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x80, 0xBF };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -333,8 +333,8 @@
// 3.1.4 - 3 continuation bytes: "\x80\xBF\x80"
{
const char* src = "\x80\xBF\x80";
- uint32_t expected[] = { 0x80, 0xBF, 0x80 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x80, 0xBF, 0x80 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -344,8 +344,8 @@
// 3.1.5 - 4 continuation bytes: "\x80\xBF\x80\xBF"
{
const char* src = "\x80\xBF\x80\xBF";
- uint32_t expected[] = { 0x80, 0xBF, 0x80, 0xBF };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x80, 0xBF, 0x80, 0xBF };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -355,8 +355,8 @@
// 3.1.6 - 5 continuation bytes: "\x80\xBF\x80\xBF\x80"
{
const char* src = "\x80\xBF\x80\xBF\x80";
- uint32_t expected[] = { 0x80, 0xBF, 0x80, 0xBF, 0x80 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x80, 0xBF, 0x80, 0xBF, 0x80 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -366,8 +366,8 @@
// 3.1.7 - 6 continuation bytes: "\x80\xBF\x80\xBF\x80\xBF"
{
const char* src = "\x80\xBF\x80\xBF\x80\xBF";
- uint32_t expected[] = { 0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -377,8 +377,8 @@
// 3.1.8 - 7 continuation bytes: "\x80\xBF\x80\xBF\x80\xBF\x80"
{
const char* src = "\x80\xBF\x80\xBF\x80\xBF\x80";
- uint32_t expected[] = { 0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF, 0x80 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF, 0x80 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -395,8 +395,8 @@
"\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF"
"\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7"
"\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF";
- uint32_t expected[] = { 0x0 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x0 };
+ int32_t dst[ARRAY_SIZE(expected)];
for (size_t i = 0; i < strlen(src); ++i) {
memset(dst, 0xFF, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(&src[i], dst, ARRAY_SIZE(dst));
@@ -418,8 +418,8 @@
"\xD4\x20\xD5\x20\xD6\x20\xD7\x20"
"\xD8\x20\xD9\x20\xDA\x20\xDB\x20"
"\xDC\x20\xDD\x20\xDE\x20\xDF\x20";
- uint32_t expected[] = { 0x0 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x0 };
+ int32_t dst[ARRAY_SIZE(expected)];
for (size_t i = 0; i < strlen(src); i += 2) {
memset(dst, 0xFF, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(&src[i], dst, ARRAY_SIZE(dst));
@@ -435,8 +435,8 @@
"\xE4\x20\xE5\x20\xE6\x20\xE7\x20"
"\xE8\x20\xE9\x20\xEA\x20\xEB\x20"
"\xEC\x20\xED\x20\xEE\x20\xEF\x20";
- uint32_t expected[] = { 0x0 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x0 };
+ int32_t dst[ARRAY_SIZE(expected)];
for (size_t i = 0; i < strlen(src); i += 2) {
memset(dst, 0xFF, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(&src[i], dst, ARRAY_SIZE(dst));
@@ -450,8 +450,8 @@
{
const char* src = "\xF0\x20\xF1\x20\xF2\x20\xF3\x20"
"\xF4\x20\xF5\x20\xF6\x20\xF7\x20";
- uint32_t expected[] = { 0x0 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x0 };
+ int32_t dst[ARRAY_SIZE(expected)];
for (size_t i = 0; i < strlen(src); i += 2) {
memset(dst, 0xFF, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(&src[i], dst, ARRAY_SIZE(dst));
@@ -464,8 +464,8 @@
// followed by a space character:
{
const char* src = "\xF8\x20\xF9\x20\xFA\x20\xFB\x20";
- uint32_t expected[] = { 0x0 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x0 };
+ int32_t dst[ARRAY_SIZE(expected)];
for (size_t i = 0; i < strlen(src); i += 2) {
memset(dst, 0xFF, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(&src[i], dst, ARRAY_SIZE(dst));
@@ -478,8 +478,8 @@
// followed by a space character:
{
const char* src = "\xFC\x20\xFD\x20";
- uint32_t expected[] = { 0x0 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x0 };
+ int32_t dst[ARRAY_SIZE(expected)];
for (size_t i = 0; i < strlen(src); i += 2) {
memset(dst, 0xFF, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(&src[i], dst, ARRAY_SIZE(dst));
@@ -493,8 +493,8 @@
// 3.3.1 - 2-byte sequence with last byte missing (U+0000): "\xC0"
{
const char* src = "\xC0";
- uint32_t expected[] = { 0x0 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x0 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0xFF, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -504,8 +504,8 @@
// 3.3.2 - 3-byte sequence with last byte missing (U+0000): "\xE0\x80"
{
const char* src = "\xE0\x80";
- uint32_t expected[] = { 0x0 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x0 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0xFF, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -515,8 +515,8 @@
// 3.3.3 - 4-byte sequence with last byte missing (U+0000): "\xF0\x80\x80"
{
const char* src = "\xF0\x80\x80";
- uint32_t expected[] = { 0x0 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x0 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0xFF, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -526,8 +526,8 @@
// 3.3.4 - 5-byte sequence with last byte missing (U+0000): "\xF8\x80\x80\x80"
{
const char* src = "\xF8\x80\x80\x80";
- uint32_t expected[] = { 0x0 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x0 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0xFF, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -538,8 +538,8 @@
// "\xFC\x80\x80\x80\x80"
{
const char* src = "\xFC\x80\x80\x80\x80";
- uint32_t expected[] = { 0x0 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x0 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0xFF, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -549,8 +549,8 @@
// 3.3.6 - 2-byte sequence with last byte missing (U-000007FF): "\xDF"
{
const char* src = "\xDF";
- uint32_t expected[] = { 0x0 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x0 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0xFF, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -560,8 +560,8 @@
// 3.3.7 - 3-byte sequence with last byte missing (U-0000FFFF): "\xEF\xBF"
{
const char* src = "\xEF\xBF";
- uint32_t expected[] = { 0x0 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x0 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0xFF, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -571,8 +571,8 @@
// 3.3.8 - 4-byte sequence with last byte missing (U-001FFFFF): "\xF7\xBF\xBF"
{
const char* src = "\xF7\xBF\xBF";
- uint32_t expected[] = { 0x0 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x0 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0xFF, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -583,8 +583,8 @@
// "\xFB\xBF\xBF\xBF"
{
const char* src = "\xFB\xBF\xBF\xBF";
- uint32_t expected[] = { 0x0 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x0 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0xFF, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -595,8 +595,8 @@
// "\xFD\xBF\xBF\xBF\xBF"
{
const char* src = "\xFD\xBF\xBF\xBF\xBF";
- uint32_t expected[] = { 0x0 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x0 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0xFF, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -610,8 +610,8 @@
"\x80\x80\x80\xDF\xEF\xBF"
"\xF7\xBF\xBF\xFB\xBF\xBF"
"\xBF\xFD\xBF\xBF\xBF\xBF";
- uint32_t expected[] = { 0x0 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x0 };
+ int32_t dst[ARRAY_SIZE(expected)];
for (size_t i = 0; i < strlen(src); ++i) {
for (size_t j = 1; j < (strlen(src) - i); ++j) {
memset(dst, 0xFF, sizeof(dst));
@@ -628,8 +628,8 @@
// 3.5.1 - fe = "\xFE"
{
const char* src = "\xFE";
- uint32_t expected[] = { 0xFE };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xFE };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -639,8 +639,8 @@
// 3.5.2 - ff = "\xFF"
{
const char* src = "\xFF";
- uint32_t expected[] = { 0xFF };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xFF };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -650,8 +650,8 @@
// 3.5.3 - fe fe ff ff = "\xFE\xFE\xFF\xFF"
{
const char* src = "\xFE\xFE\xFF\xFF";
- uint32_t expected[] = { 0xFF };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xFF };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -665,8 +665,8 @@
// 4.1.1 - U+002F = c0 af = "\xC0\xAF"
{
const char* src = "\xC0\xAF";
- uint32_t expected[] = { 0x2F };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x2F };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -676,8 +676,8 @@
// 4.1.2 - U+002F = e0 80 af = "\xE0\x80\xAF"
{
const char* src = "\xE0\x80\xAF";
- uint32_t expected[] = { 0x2F };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x2F };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -687,8 +687,8 @@
// 4.1.3 - U+002F = f0 80 80 af = "\xF0\x80\x80\xAF"
{
const char* src = "\xF0\x80\x80\xAF";
- uint32_t expected[] = { 0x2F };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x2F };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -698,8 +698,8 @@
// 4.1.4 - U+002F = f8 80 80 80 af = "\xF8\x80\x80\x80\xAF"
{
const char* src = "\xF8\x80\x80\x80\xAF";
- uint32_t expected[] = { 0x2F };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x2F };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -709,8 +709,8 @@
// 4.1.5 - U+002F = fc 80 80 80 80 af = "\xFC\x80\x80\x80\x80\xAF"
{
const char* src = "\xFC\x80\x80\x80\x80\xAF";
- uint32_t expected[] = { 0x2F };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x2F };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -722,8 +722,8 @@
// 4.2.1 - U-0000007F = c1 bf = "\xC1\xBF"
{
const char* src = "\xC1\xBF";
- uint32_t expected[] = { 0x7F };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x7F };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -733,8 +733,8 @@
// 4.2.2 U+000007FF = e0 9f bf = "\xE0\x9F\xBF"
{
const char* src = "\xE0\x9F\xBF";
- uint32_t expected[] = { 0x7FF };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x7FF };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -744,8 +744,8 @@
// 4.2.3 - U+0000FFFF = f0 8f bf bf = "\xF0\x8F\xBF\xBF"
{
const char* src = "\xF0\x8F\xBF\xBF";
- uint32_t expected[] = { 0xFFFF };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xFFFF };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -755,8 +755,8 @@
// 4.2.4 U-001FFFFF = f8 87 bf bf bf = "\xF8\x87\xBF\xBF\xBF"
{
const char* src = "\xF8\x87\xBF\xBF\xBF";
- uint32_t expected[] = { 0x1FFFFF };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x1FFFFF };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -766,8 +766,8 @@
// 4.2.5 U-03FFFFFF = fc 83 bf bf bf bf = "\xFC\x83\xBF\xBF\xBF\xBF"
{
const char* src = "\xFC\x83\xBF\xBF\xBF\xBF";
- uint32_t expected[] = { 0x3FFFFFF };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x3FFFFFF };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -779,8 +779,8 @@
// 4.3.1 - U+0000 = "\xC0\x80"
{
const char* src = "\xC0\x80";
- uint32_t expected[] = { 0x0 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x0 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0xFF, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -790,8 +790,8 @@
// 4.3.2 U+0000 = e0 80 80 = "\xE0\x80\x80"
{
const char* src = "\xE0\x80\x80";
- uint32_t expected[] = { 0x0 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x0 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0xFF, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -801,8 +801,8 @@
// 4.3.3 U+0000 = f0 80 80 80 = "\xF0\x80\x80\x80"
{
const char* src = "\xF0\x80\x80\x80";
- uint32_t expected[] = { 0x0 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x0 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0xFF, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -812,8 +812,8 @@
// 4.3.4 U+0000 = f8 80 80 80 80 = "\xF8\x80\x80\x80\x80"
{
const char* src = "\xF8\x80\x80\x80\x80";
- uint32_t expected[] = { 0x0 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x0 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0xFF, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -823,8 +823,8 @@
// 4.3.5 U+0000 = fc 80 80 80 80 80 = "\xFC\x80\x80\x80\x80\x80"
{
const char* src = "\xFC\x80\x80\x80\x80\x80";
- uint32_t expected[] = { 0x0 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0x0 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0xFF, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -836,8 +836,8 @@
// 5.1.1 - U+D800 = ed a0 80 = "\xED\xA0\x80"
{
const char* src = "\xED\xA0\x80";
- uint32_t expected[] = { 0xD800 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xD800 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -847,8 +847,8 @@
// 5.1.2 - U+DB7F = ed ad bf = "\xED\xAD\xBF"
{
const char* src = "\xED\xAD\xBF";
- uint32_t expected[] = { 0xDB7F };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xDB7F };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -858,8 +858,8 @@
// 5.1.3 - U+DB80 = ed ae 80 = "\xED\xAE\x80"
{
const char* src = "\xED\xAE\x80";
- uint32_t expected[] = { 0xDB80 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xDB80 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -869,8 +869,8 @@
// 5.1.4 - U+DBFF = ed af bf = "\xED\xAF\xBF"
{
const char* src = "\xED\xAF\xBF";
- uint32_t expected[] = { 0xDBFF };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xDBFF };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -880,8 +880,8 @@
// 5.1.5 - U+DC00 = ed b0 80 = "\xED\xB0\x80"
{
const char* src = "\xED\xB0\x80";
- uint32_t expected[] = { 0xDC00 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xDC00 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -891,8 +891,8 @@
// 5.1.6 - U+DF80 = ed be 80 = "\xED\xBE\x80"
{
const char* src = "\xED\xBE\x80";
- uint32_t expected[] = { 0xDF80 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xDF80 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -902,8 +902,8 @@
// 5.1.7 - U+DFFF = ed bf bf = "\xED\xBF\xBF"
{
const char* src = "\xED\xBF\xBF";
- uint32_t expected[] = { 0xDFFF };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xDFFF };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -915,8 +915,8 @@
// 5.2.1 - U+D800 U+DC00 = ed a0 80 ed b0 80 = "\xED\xA0\x80\xED\xB0\x80"
{
const char* src = "\xED\xA0\x80\xED\xB0\x80";
- uint32_t expected[] = { 0xD800, 0xDC00 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xD800, 0xDC00 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -926,8 +926,8 @@
// 5.2.2 - U+D800 U+DFFF = ed a0 80 ed bf bf = "\xED\xA0\x80\xED\xBF\xBF"
{
const char* src = "\xED\xA0\x80\xED\xBF\xBF";
- uint32_t expected[] = { 0xD800, 0xDFFF };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xD800, 0xDFFF };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -937,8 +937,8 @@
// 5.2.3 - U+DB7F U+DC00 = ed a0 80 ed bf bf = "\xED\xAD\xBF\xED\xB0\x80"
{
const char* src = "\xED\xAD\xBF\xED\xB0\x80";
- uint32_t expected[] = { 0xDB7F, 0xDC00 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xDB7F, 0xDC00 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -948,8 +948,8 @@
// 5.2.4 - U+DB7F U+DFFF = ed ad bf ed bf bf = "\xED\xAD\xBF\xED\xBF\xBF"
{
const char* src = "\xED\xAD\xBF\xED\xBF\xBF";
- uint32_t expected[] = { 0xDB7F, 0xDFFF };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xDB7F, 0xDFFF };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -959,8 +959,8 @@
// 5.2.5 - U+DB80 U+DC00 = ed ae 80 ed b0 80 = "\xED\xAE\x80\xED\xB0\x80"
{
const char* src = "\xED\xAE\x80\xED\xB0\x80";
- uint32_t expected[] = { 0xDB80, 0xDC00 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xDB80, 0xDC00 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -970,8 +970,8 @@
// 5.2.6 - U+DB80 U+DFFF = ed ae 80 ed bf bf = "\xED\xAE\x80\xED\xBF\xBF"
{
const char* src = "\xED\xAE\x80\xED\xBF\xBF";
- uint32_t expected[] = { 0xDB80, 0xDFFF };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xDB80, 0xDFFF };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -981,8 +981,8 @@
// 5.2.7 - U+DBFF U+DC00 = ed af bf ed b0 80 = "\xED\xAF\xBF\xED\xB0\x80"
{
const char* src = "\xED\xAF\xBF\xED\xB0\x80";
- uint32_t expected[] = { 0xDBFF, 0xDC00 };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xDBFF, 0xDC00 };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -992,8 +992,8 @@
// 5.2.8 - U+DBFF U+DFFF = ed af bf ed bf bf = "\xED\xAF\xBF\xED\xBF\xBF"
{
const char* src = "\xED\xAF\xBF\xED\xBF\xBF";
- uint32_t expected[] = { 0xDBFF, 0xDFFF };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xDBFF, 0xDFFF };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(!is_valid);
@@ -1005,8 +1005,8 @@
// 5.3.1 - U+FFFE = ef bf be = "\xEF\xBF\xBE"
{
const char* src = "\xEF\xBF\xBE";
- uint32_t expected[] = { 0xFFFE };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xFFFE };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(is_valid);
@@ -1016,8 +1016,8 @@
// 5.3.2 - U+FFFF = ef bf bf = "\xEF\xBF\xBF"
{
const char* src = "\xEF\xBF\xBF";
- uint32_t expected[] = { 0xFFFF };
- uint32_t dst[ARRAY_SIZE(expected)];
+ int32_t expected[] = { 0xFFFF };
+ int32_t dst[ARRAY_SIZE(expected)];
memset(dst, 0, sizeof(dst));
bool is_valid = Utf8::DecodeCStringToUTF32(src, dst, ARRAY_SIZE(dst));
EXPECT(is_valid);
diff --git a/runtime/vm/vm.gypi b/runtime/vm/vm.gypi
index 0fb1bd9..7104aa5 100644
--- a/runtime/vm/vm.gypi
+++ b/runtime/vm/vm.gypi
@@ -78,6 +78,7 @@
'includes': [
'../lib/lib_sources.gypi',
'../lib/isolate_sources.gypi',
+ '../lib/math_sources.gypi',
'../lib/mirrors_sources.gypi',
'../lib/scalarlist_sources.gypi',
],
@@ -106,6 +107,7 @@
'includes': [
'../lib/lib_sources.gypi',
'../lib/isolate_sources.gypi',
+ '../lib/math_sources.gypi',
'../lib/mirrors_sources.gypi',
'../lib/scalarlist_sources.gypi',
],
diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi
index d45c8fa..2b2f9d4 100644
--- a/runtime/vm/vm_sources.gypi
+++ b/runtime/vm/vm_sources.gypi
@@ -236,9 +236,6 @@
'port.cc',
'port.h',
'port_test.cc',
- 'random.cc',
- 'random.h',
- 'random_test.cc',
'raw_object.cc',
'raw_object.h',
'raw_object_snapshot.cc',
diff --git a/sdk/lib/_internal/compiler/compiler.dart b/sdk/lib/_internal/compiler/compiler.dart
index af37116..9ef6aa8 100644
--- a/sdk/lib/_internal/compiler/compiler.dart
+++ b/sdk/lib/_internal/compiler/compiler.dart
@@ -8,8 +8,7 @@
import 'implementation/apiimpl.dart';
// Unless explicitly allowed, passing [:null:] for any argument to the
-// methods of library will result in a NullPointerException being
-// thrown.
+// methods of library will result in an Error being thrown.
/**
* Returns a future that completes to the source corresponding to
diff --git a/sdk/lib/_internal/compiler/implementation/closure.dart b/sdk/lib/_internal/compiler/implementation/closure.dart
index 4d6be1c..3d5feef 100644
--- a/sdk/lib/_internal/compiler/implementation/closure.dart
+++ b/sdk/lib/_internal/compiler/implementation/closure.dart
@@ -371,7 +371,7 @@
return true;
} else if (type is InterfaceType) {
InterfaceType ifcType = type;
- for (DartType argument in ifcType.arguments) {
+ for (DartType argument in ifcType.typeArguments) {
if (hasTypeVariable(argument)) {
return true;
}
@@ -385,7 +385,7 @@
useLocal(type.element);
} else if (type is InterfaceType) {
InterfaceType ifcType = type;
- for (DartType argument in ifcType.arguments) {
+ for (DartType argument in ifcType.typeArguments) {
analyzeTypeVariables(argument);
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
index 1f16080..975d4e5 100644
--- a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
+++ b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
@@ -28,7 +28,6 @@
/** Caches the statics where the initial value cannot be eagerly compiled. */
final Set<VariableElement> lazyStatics;
-
ConstantHandler(Compiler compiler, this.constantSystem)
: initialVariableValues = new Map<VariableElement, dynamic>(),
compiledConstants = new Set<Constant>(),
@@ -134,7 +133,7 @@
&& element.isField()) {
DartType elementType = element.computeType(compiler);
DartType constantType = value.computeType(compiler);
- if (!compiler.types.isSubtype(constantType, elementType)) {
+ if (!constantSystem.isSubtype(compiler, constantType, elementType)) {
if (isConst) {
MessageKind kind = MessageKind.NOT_ASSIGNABLE;
compiler.reportError(node, new CompileTimeConstantError(
@@ -248,6 +247,7 @@
final ConstantSystem constantSystem;
final TreeElements elements;
final Compiler compiler;
+ bool enabledRuntimeTypeSupport = false;
CompileTimeConstantEvaluator(this.constantSystem,
this.elements,
@@ -400,6 +400,25 @@
return constantSystem.createString(accumulator, node);
}
+ Constant makeTypeConstant(Element element) {
+ // If we use a type literal in a constant, the compile time constant
+ // emitter will generate a call to the runtime type cache helper, so we
+ // resolve it and put it into the codegen work list.
+ if (!enabledRuntimeTypeSupport) {
+ SourceString helperName = const SourceString('createRuntimeType');
+ Element helper = compiler.findHelper(helperName);
+ compiler.enqueuer.resolution.addToWorkList(helper);
+ compiler.enqueuer.codegen.addToWorkList(helper);
+ enabledRuntimeTypeSupport = true;
+ }
+
+ DartType elementType = element.computeType(compiler).asRaw();
+ DartType constantType = compiler.typeClass.computeType(compiler);
+ Constant constant = new TypeConstant(elementType, constantType);
+ compiler.constantHandler.registerCompileTimeConstant(constant);
+ return constant;
+ }
+
// TODO(floitsch): provide better error-messages.
Constant visitSend(Send send) {
Element element = elements[send];
@@ -418,6 +437,8 @@
result = compiler.compileVariable(element);
}
if (result != null) return result;
+ } else if (Elements.isClass(element) || Elements.isTypedef(element)) {
+ return makeTypeConstant(element);
}
return signalNotCompileTimeConstant(send);
} else if (send.isCall) {
@@ -427,6 +448,8 @@
Constant right = evaluate(send.argumentsNode.nodes.tail.head);
Constant result = constantSystem.identity.fold(left, right);
if (result != null) return result;
+ } else if (Elements.isClass(element) || Elements.isTypedef(element)) {
+ return makeTypeConstant(element);
}
return signalNotCompileTimeConstant(send);
} else if (send.isPrefix) {
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index e416804..e770cff 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -96,8 +96,6 @@
SourceString getCheckedModeHelper(DartType type) => null;
void registerInstantiatedClass(ClassElement cls, Enqueuer enqueuer) {}
-
- Element getInterceptor(Selector selector);
}
abstract class Compiler implements DiagnosticListener {
diff --git a/sdk/lib/_internal/compiler/implementation/constants.dart b/sdk/lib/_internal/compiler/implementation/constants.dart
index 6e20124..ad5dc74 100644
--- a/sdk/lib/_internal/compiler/implementation/constants.dart
+++ b/sdk/lib/_internal/compiler/implementation/constants.dart
@@ -16,6 +16,7 @@
R visitList(ListConstant constant);
R visitMap(MapConstant constant);
R visitConstructed(ConstructedConstant constant);
+ R visitType(TypeConstant constant);
}
abstract class Constant {
@@ -37,6 +38,7 @@
bool isPrimitive() => false;
/** Returns true if the constant is a list, a map or a constructed object. */
bool isObject() => false;
+ bool isType() => false;
bool isSentinel() => false;
bool isNaN() => false;
@@ -46,7 +48,7 @@
List<Constant> getDependencies();
- accept(ConstantVisitor);
+ accept(ConstantVisitor visitor);
}
class SentinelConstant extends Constant {
@@ -100,7 +102,7 @@
bool operator ==(var other) {
if (other is !PrimitiveConstant) return false;
PrimitiveConstant otherPrimitive = other;
- // We use == instead of === so that DartStrings compare correctly.
+ // We use == instead of 'identical' so that DartStrings compare correctly.
return value == otherPrimitive.value;
}
@@ -315,10 +317,25 @@
bool isObject() => true;
DartType computeType(Compiler compiler) => type;
+}
- // TODO(1603): The class should be marked as abstract, but the VM doesn't
- // currently allow this.
- int get hashCode;
+class TypeConstant extends ObjectConstant {
+ /// The user type that this constant represents.
+ final DartType representedType;
+
+ TypeConstant(this.representedType, type) : super(type);
+
+ bool isType() => true;
+
+ bool operator ==(other) {
+ return other is TypeConstant && representedType == other.representedType;
+ }
+
+ int get hashCode => representedType.hashCode * 13;
+
+ List<Constant> getDependencies() => const <Constant>[];
+
+ accept(ConstantVisitor visitor) => visitor.visitType(this);
}
class ListConstant extends ObjectConstant {
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
index 101918b..c012488 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
@@ -196,8 +196,6 @@
stripAsserts = strips.indexOf('asserts') != -1,
super(compiler);
- Element getInterceptor(Selector selector) => null;
-
void enqueueHelpers(Enqueuer world) {
// Right now resolver doesn't always resolve interfaces needed
// for literals, so force them. TODO(antonm): fix in the resolver.
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
index b31e471..63e14f9 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
@@ -30,6 +30,7 @@
final bool isRedirectingCall;
ConstructorPlaceholder(this.node, this.type)
: this.isRedirectingCall = false;
+ // Note: factory redirection is not redirecting call!
ConstructorPlaceholder.redirectingCall(this.node)
: this.type = null, this.isRedirectingCall = true;
}
@@ -141,7 +142,7 @@
final Set<String> fixedMemberNames; // member names which cannot be renamed.
final Map<Element, ElementAst> elementAsts;
final Set<Node> nullNodes; // Nodes that should not be in output.
- final Set<Identifier> unresolvedNodes;
+ final Set<Node> unresolvedNodes;
final Map<Element, Set<Node>> elementNodes;
final Map<FunctionElement, FunctionScope> functionScopes;
final Map<LibraryElement, Set<Identifier>> privateNodes;
@@ -161,7 +162,7 @@
PlaceholderCollector(this.compiler, this.fixedMemberNames, this.elementAsts) :
nullNodes = new Set<Node>(),