Make a fork of sdk/lib for use by NNBD.

Change-Id: I7f5892d66f9e7bd08ca064fb2df329794a56faf5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/116527
Reviewed-by: Leaf Petersen <leafp@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
This commit is contained in:
Paul Berry 2019-09-10 19:20:12 +00:00 committed by commit-bot@chromium.org
parent ca7baa4013
commit 004d49bd6b
322 changed files with 165262 additions and 0 deletions

1069
sdk_nnbd/BUILD.gn Normal file

File diff suppressed because it is too large Load diff

32
sdk_nnbd/api_readme.md Normal file
View file

@ -0,0 +1,32 @@
Welcome to the Dart API reference documentation, covering the core Dart API
libraries. Some of the most fundamental Dart libraries include:
* [dart:core](dart-core/dart-core-library.html): Core functionality such as
strings, numbers, collections, errors, dates, and URIs.
* [dart:html](dart-html/dart-html-library.html): DOM manipulation for web apps
(available only to web apps).
* [dart:io](dart-io/dart-io-library.html): I/O for non-web apps.
Except for `dart:core`, you must import a library before you can use it. Here's
an example of importing `dart:async` and `dart:math`:
```dart
import 'dart:async';
import 'dart:math';
```
You can install more libraries using the
[pub package manager](https://dart.dev/guides/packages).
The main site for learning and using Dart is
[dart.dev](https://dart.dev). Check out these pages:
* [Platforms](https://dart.dev/platforms)
* [Language tour](https://dart.dev/guides/language/language-tour)
* [Library tour](https://dart.dev/guides/libraries/library-tour)
* [Sample code](https://dart.dev/samples)
This API reference is automatically generated from source code in the [Dart
SDK project](https://github.com/dart-lang/sdk).
If you'd like to give feedback or edit this documentation, see
[Contributing](https://github.com/dart-lang/sdk/wiki/Contributing).

57
sdk_nnbd/bin/dart Executable file
View file

@ -0,0 +1,57 @@
#!/usr/bin/env bash
# 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.
function follow_links() {
file="$1"
while [ -h "$file" ]; do
# On Mac OS, readlink -f doesn't work.
file="$(readlink "$file")"
done
echo "$file"
}
# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
PROG_NAME="$(follow_links "$BASH_SOURCE")"
# Handle the case where dart-sdk/bin has been symlinked to.
CUR_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
if [[ `uname` == 'Darwin' ]];
then
OUT_DIR="$CUR_DIR"/../../xcodebuild/
else
OUT_DIR="$CUR_DIR"/../../out/
fi
if [ -z "$DART_CONFIGURATION" ];
then
DIRS=$( ls "$OUT_DIR" )
# list of possible configurations in decreasing desirability
CONFIGS=("ReleaseX64" "ReleaseIA32" "DebugX64" "DebugIA32"
"ReleaseARM" "ReleaseARM64" "ReleaseARMV5TE"
"DebugARM" "DebugARM64" "DebugARMV5TE")
DART_CONFIGURATION="None"
for CONFIG in ${CONFIGS[*]}
do
for DIR in $DIRS;
do
if [ "$CONFIG" = "$DIR" ];
then
# choose most desirable configuration that is available and break
DART_CONFIGURATION="$DIR"
break 2
fi
done
done
if [ "$DART_CONFIGURATION" = "None" ]
then
echo "No valid dart configuration found in $OUT_DIR"
exit 1
fi
fi
BIN_DIR="$OUT_DIR$DART_CONFIGURATION"
exec "$BIN_DIR"/dart "$@"

16
sdk_nnbd/bin/dart.bat Normal file
View file

@ -0,0 +1,16 @@
@echo off
REM Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
REM for details. All rights reserved. Use of this source code is governed by a
REM BSD-style license that can be found in the LICENSE file.
set SCRIPTPATH=%~dp0
REM Does the path have a trailing slash? If so, remove it.
if %SCRIPTPATH:~-1%== set SCRIPTPATH=%SCRIPTPATH:~0,-1%
REM DART_CONFIGURATION defaults to ReleaseX64
if "%DART_CONFIGURATION%"=="" set DART_CONFIGURATION=ReleaseX64
set arguments=%*
"%SCRIPTPATH%\..\..\out\%DART_CONFIGURATION%\dart.exe" %arguments%

111
sdk_nnbd/bin/dart2aot Executable file
View file

@ -0,0 +1,111 @@
#!/usr/bin/env bash
# Copyright (c) 2019, 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.
# Script for generating AOT snapshot in two steps:
# - Compilation to kernel with additional AOT specific transformations.
# - Compilation of kernel into snapshot using gen_snapshot.
# Parse incoming arguments and extract the value of --packages option if any
# was passed. Split options (--xyz) and non-options into two separate arrays.
# All options will be passed to gen_snapshot, while --packages will be
# passed to the CFE (Common Front-End).
set -e
OPTIONS=()
GEN_KERNEL_OPTIONS=()
PACKAGES=
BUILD_ELF=0
ARGV=()
for arg in "$@"; do
case $arg in
--packages=*)
PACKAGES="$arg"
;;
--enable-asserts)
GEN_KERNEL_OPTIONS+=("$arg")
OPTIONS+=("$arg")
;;
--tfa | \
--no-tfa | \
-D* )
GEN_KERNEL_OPTIONS+=("$arg")
;;
--build-elf)
BUILD_ELF=1
;;
--*)
OPTIONS+=("$arg")
;;
*)
ARGV+=("$arg")
;;
esac
done
if [ "${#ARGV[@]}" -ne 2 ]; then
echo "Usage: $0 [options] <dart-source-file> <dart-aot-file>"
echo ""
echo "Dart AOT (ahead-of-time) compile Dart source code into native machine code."
exit 1
fi
SOURCE_FILE="${ARGV[0]}"
SNAPSHOT_FILE="${ARGV[1]}"
if [ $BUILD_ELF -eq 1 ]; then
GEN_SNAPSHOT_OPTION="--snapshot-kind=app-aot-assembly"
GEN_SNAPSHOT_FILENAME="--assembly=${SNAPSHOT_FILE}.S"
else
GEN_SNAPSHOT_OPTION="--snapshot-kind=app-aot-blobs"
GEN_SNAPSHOT_FILENAME="--blobs_container_filename=${SNAPSHOT_FILE}"
fi
function follow_links() {
file="$1"
while [ -h "$file" ]; do
# On Mac OS, readlink -f doesn't work.
file="$(readlink "$file")"
done
echo "$file"
}
# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
PROG_NAME="$(follow_links "$BASH_SOURCE")"
# Handle the case where dart-sdk/bin has been symlinked to.
BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
DART="$BIN_DIR/dart"
GEN_SNAPSHOT="$BIN_DIR/utils/gen_snapshot"
SNAPSHOT_DIR="$BIN_DIR/snapshots"
SNAPSHOT="$SNAPSHOT_DIR/gen_kernel.dart.snapshot"
# Step 1: Generate Kernel binary from the input Dart source.
"$DART" \
"${SNAPSHOT}" \
--platform "${SDK_DIR}/lib/_internal/vm_platform_strong.dill" \
--aot \
-Ddart.vm.product=true \
"${GEN_KERNEL_OPTIONS[@]}" \
$PACKAGES \
-o "$SNAPSHOT_FILE.dill" \
"$SOURCE_FILE"
# Step 2: Generate snapshot from the Kernel binary.
"$GEN_SNAPSHOT" \
"$GEN_SNAPSHOT_OPTION" \
"$GEN_SNAPSHOT_FILENAME" \
"${OPTIONS[@]}" \
"$SNAPSHOT_FILE.dill"
# Step 3: Assemble the assembly file into an ELF object.
if [ $BUILD_ELF -eq 1 ]; then
gcc -shared -o "$SNAPSHOT_FILE" "${SNAPSHOT_FILE}.S"
fi

58
sdk_nnbd/bin/dart2aot.bat Normal file
View file

@ -0,0 +1,58 @@
@echo off
REM Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
REM for details. All rights reserved. Use of this source code is governed by a
REM BSD-style license that can be found in the LICENSE file.
setlocal
rem Handle the case where dart-sdk/bin has been symlinked to.
set DIR_NAME_WITH_SLASH=%~dp0
set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
rem Get rid of surrounding quotes.
for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
rem Get absolute full name for SDK_DIR.
for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
rem Remove trailing backslash if there is one
IF %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
rem Get absolute full name for DART_ROOT.
for %%i in ("%SDK_DIR%\..\") do set DART_ROOT=%%~fi
rem Remove trailing backslash if there is one
if %DART_ROOT:~-1%==\ set DART_ROOT=%DART_ROOT:~0,-1%
set DART=%BIN_DIR%\dart.exe
set GEN_KERNEL=%BIN_DIR%\snapshots\gen_kernel.dart.snapshot
set VM_PLATFORM_STRONG=%SDK_DIR%\lib\_internal\vm_platform_strong.dill
set GEN_SNAPSHOT=%BIN_DIR%\utils\gen_snapshot.exe
set SOURCE_FILE=%1
set SNAPSHOT_FILE=%2
set GEN_SNAPSHOT_OPTION=--snapshot-kind=app-aot-blobs
set GEN_SNAPSHOT_FILENAME=--blobs_container_filename=%SNAPSHOT_FILE%
REM Step 1: Generate Kernel binary from the input Dart source.
%DART% %GEN_KERNEL% --platform %VM_PLATFORM_STRONG% --aot -Ddart.vm.product=true -o %SNAPSHOT_FILE%.dill %SOURCE_FILE%
REM Step 2: Generate snapshot from the Kernel binary.
%GEN_SNAPSHOT% %GEN_SNAPSHOT_OPTION% %GEN_SNAPSHOT_FILENAME% %SNAPSHOT_FILE%.dill
endlocal
exit /b %errorlevel%
:follow_links
setlocal
for %%i in (%1) do set result=%%~fi
set current=
for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
^| %SystemRoot%\System32\find.exe "> %~n1 [" 2^>nul`) do (
set current=%%i
)
if not "%current%"=="" call :follow_links "%current%", result
endlocal & set %~2=%result%
goto :eof
:end

55
sdk_nnbd/bin/dart2js Executable file
View file

@ -0,0 +1,55 @@
#!/usr/bin/env bash
# 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.
function follow_links() {
file="$1"
while [ -h "$file" ]; do
# On Mac OS, readlink -f doesn't work.
file="$(readlink "$file")"
done
echo "$file"
}
# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
PROG_NAME="$(follow_links "$BASH_SOURCE")"
# Handle the case where dart-sdk/bin has been symlinked to.
BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
DART="$BIN_DIR/dart"
unset EXTRA_OPTIONS
declare -a EXTRA_OPTIONS
if test -t 1; then
# Stdout is a terminal.
if test 8 -le `tput colors`; then
# Stdout has at least 8 colors, so enable colors.
EXTRA_OPTIONS+=('--enable-diagnostic-colors')
fi
fi
unset EXTRA_VM_OPTIONS
declare -a EXTRA_VM_OPTIONS
case $0 in
*_developer)
EXTRA_VM_OPTIONS+=('--enable-asserts')
;;
esac
# We allow extra vm options to be passed in through an environment variable.
if [[ $DART_VM_OPTIONS ]]; then
read -a OPTIONS <<< "$DART_VM_OPTIONS"
EXTRA_VM_OPTIONS+=("${OPTIONS[@]}")
fi
DART_ROOT="$(cd "${SDK_DIR}/.." ; pwd -P)"
DART2JS="package:compiler/src/dart2js.dart"
exec "$DART" "--packages=$DART_ROOT/.packages" "${EXTRA_VM_OPTIONS[@]}" "$DART2JS" "${EXTRA_OPTIONS[@]}" "$@"

60
sdk_nnbd/bin/dart2js.bat Normal file
View file

@ -0,0 +1,60 @@
@echo off
REM Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
REM for details. All rights reserved. Use of this source code is governed by a
REM BSD-style license that can be found in the LICENSE file.
setlocal
rem Handle the case where dart-sdk/bin has been symlinked to.
set DIR_NAME_WITH_SLASH=%~dp0
set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
rem Get rid of surrounding quotes.
for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
rem Get absolute full name for SDK_DIR.
for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
rem Remove trailing backslash if there is one
IF %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
set DART=%BIN_DIR%\dart
set EXTRA_OPTIONS=
set EXTRA_VM_OPTIONS=
if _%DART2JS_DEVELOPER_MODE%_ == _1_ (
set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% --enable-asserts
)
rem We allow extra vm options to be passed in through an environment variable.
if not "_%DART_VM_OPTIONS%_" == "__" (
set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% %DART_VM_OPTIONS%
)
rem Get absolute full name for DART_ROOT.
for %%i in ("%SDK_DIR%\..\") do set DART_ROOT=%%~fi
rem Remove trailing backslash if there is one
if %DART_ROOT:~-1%==\ set DART_ROOT=%DART_ROOT:~0,-1%
set DART2JS=%DART_ROOT%\pkg\compiler\lib\src\dart2js.dart
"%DART%" "--packages=%DART_ROOT%\.packages" %EXTRA_VM_OPTIONS% "%DART2JS%" %EXTRA_OPTIONS% %*
endlocal
exit /b %errorlevel%
:follow_links
setlocal
for %%i in (%1) do set result=%%~fi
set current=
for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
^| %SystemRoot%\System32\find.exe "> %~n1 [" 2^>nul`) do (
set current=%%i
)
if not "%current%"=="" call :follow_links "%current%", result
endlocal & set %~2=%result%
goto :eof
:end

6
sdk_nnbd/bin/dart2js_developer Executable file
View file

@ -0,0 +1,6 @@
#!/usr/bin/env bash
# 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.
. ${BASH_SOURCE%_developer}

View file

@ -0,0 +1,10 @@
@echo off
REM Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
REM for details. All rights reserved. Use of this source code is governed by a
REM BSD-style license that can be found in the LICENSE file.
setlocal
set DART2JS_DEVELOPER_MODE=1
call "%~dp0dart2js.bat" %*
endlocal
exit /b %errorlevel%

58
sdk_nnbd/bin/dart2js_sdk Executable file
View file

@ -0,0 +1,58 @@
#!/usr/bin/env bash
# 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.
function follow_links() {
file="$1"
while [ -h "$file" ]; do
# On Mac OS, readlink -f doesn't work.
file="$(readlink "$file")"
done
echo "$file"
}
# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
PROG_NAME="$(follow_links "$BASH_SOURCE")"
# Handle the case where dart-sdk/bin has been symlinked to.
BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
DART="$BIN_DIR/dart"
SNAPSHOT_DIR="$BIN_DIR/snapshots"
SNAPSHOT="$SNAPSHOT_DIR/dart2js.dart.snapshot"
unset EXTRA_OPTIONS
declare -a EXTRA_OPTIONS
if test -t 1; then
# Stdout is a terminal.
if test 8 -le `tput colors`; then
# Stdout has at least 8 colors, so enable colors.
EXTRA_OPTIONS+=('--enable-diagnostic-colors')
fi
fi
unset EXTRA_VM_OPTIONS
declare -a EXTRA_VM_OPTIONS
if test -f "$SNAPSHOT"; then
EXTRA_OPTIONS+=("--libraries-spec=$SDK_DIR/lib/libraries.json")
fi
case $0 in
*_developer)
EXTRA_VM_OPTIONS+=('--enable-asserts')
;;
esac
# We allow extra vm options to be passed in through an environment variable.
if [[ $DART_VM_OPTIONS ]]; then
read -a OPTIONS <<< "$DART_VM_OPTIONS"
EXTRA_VM_OPTIONS+=("${OPTIONS[@]}")
fi
exec "$DART" "${EXTRA_VM_OPTIONS[@]}" "$SNAPSHOT" "${EXTRA_OPTIONS[@]}" "$@"

57
sdk_nnbd/bin/dart2js_sdk.bat Executable file
View file

@ -0,0 +1,57 @@
@echo off
REM Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
REM for details. All rights reserved. Use of this source code is governed by a
REM BSD-style license that can be found in the LICENSE file.
setlocal
rem Handle the case where dart-sdk/bin has been symlinked to.
set DIR_NAME_WITH_SLASH=%~dp0
set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
rem Get rid of surrounding quotes.
for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
rem Get absolute full name for SDK_DIR.
for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
rem Remove trailing backslash if there is one
IF %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
set DART=%BIN_DIR%\dart
set SNAPSHOT=%BIN_DIR%\snapshots\dart2js.dart.snapshot
set EXTRA_OPTIONS=
set EXTRA_VM_OPTIONS=
if _%DART2JS_DEVELOPER_MODE%_ == _1_ (
set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% --enable-asserts
)
if exist "%SNAPSHOT%" (
set EXTRA_OPTIONS=%EXTRA_OPTIONS% "--libraries-spec=%SDK_DIR%\lib\libraries.json"
)
rem We allow extra vm options to be passed in through an environment variable.
if not "_%DART_VM_OPTIONS%_" == "__" (
set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% %DART_VM_OPTIONS%
)
"%DART%" %EXTRA_VM_OPTIONS% "%SNAPSHOT%" %EXTRA_OPTIONS% %*
endlocal
exit /b %errorlevel%
:follow_links
setlocal
for %%i in (%1) do set result=%%~fi
set current=
for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
^| find "> %~n1 [" 2^>nul`) do (
set current=%%i
)
if not "%current%"=="" call :follow_links "%current%", result
endlocal & set %~2=%result%
goto :eof
:end

25
sdk_nnbd/bin/dart2native Executable file
View file

@ -0,0 +1,25 @@
#!/usr/bin/env bash
# Copyright (c) 2019, 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.
# Run dart2native.dart.snapshot on the Dart VM
function follow_links() {
file="$1"
while [ -h "$file" ]; do
# On Mac OS, readlink -f doesn't work.
file="$(readlink "$file")"
done
echo "$file"
}
# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
PROG_NAME="$(follow_links "$BASH_SOURCE")"
# Handle the case where dart-sdk/bin has been symlinked to.
BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
SNAPSHOTS_DIR="${BIN_DIR}/snapshots"
DART="$BIN_DIR/dart"
exec "$DART" "${SNAPSHOTS_DIR}/dart2native.dart.snapshot" $*

View file

@ -0,0 +1,43 @@
@echo off
REM Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
REM for details. All rights reserved. Use of this source code is governed by a
REM BSD-style license that can be found in the LICENSE file.
setlocal
rem Handle the case where dart-sdk/bin has been symlinked to.
set DIR_NAME_WITH_SLASH=%~dp0
set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
rem Get rid of surrounding quotes.
for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
set DART=%BIN_DIR%\dart
"%DART%" "%BIN_DIR%\snapshots\dart2native.dart.snapshot" %*
endlocal
exit /b %errorlevel%
rem Follow the symbolic links (junctions points) using `dir to determine the
rem canonical path. Output with a link looks something like this
rem
rem 01/03/2013 10:11 PM <JUNCTION> abc def
rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
rem
rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
rem surrounded by right angle bracket and left square bracket. Once we get
rem the filename, which is name of the link, we recursively follow that.
:follow_links
setlocal
for %%i in (%1) do set result=%%~fi
set current=
for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
^| %SystemRoot%\System32\find.exe "> %~n1 [" 2^>nul`) do (
set current=%%i
)
if not "%current%"=="" call :follow_links "%current%", result
endlocal & set %~2=%result%
goto :eof
:end

50
sdk_nnbd/bin/dartanalyzer Executable file
View file

@ -0,0 +1,50 @@
#!/usr/bin/env bash
# Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
# Run dartanalyzer.dart on the Dart VM. This script assumes the Dart repo's
# directory structure.
function follow_links() {
file="$1"
while [ -h "$file" ]; do
# On Mac OS, readlink -f doesn't work.
file="$(readlink "$file")"
done
echo "$file"
}
# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
PROG_NAME="$(follow_links "$BASH_SOURCE")"
# Handle the case where dart-sdk/bin has been symlinked to.
BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
SDK_ARG="--dart-sdk=$SDK_DIR"
DART="$BIN_DIR/dart"
unset EXTRA_VM_OPTIONS
declare -a EXTRA_VM_OPTIONS
case $0 in
*_developer)
EXTRA_VM_OPTIONS+=('--enable-asserts')
;;
esac
# We allow extra vm options to be passed in through an environment variable.
if [[ $DART_VM_OPTIONS ]]; then
read -a OPTIONS <<< "$DART_VM_OPTIONS"
EXTRA_VM_OPTIONS+=("${OPTIONS[@]}")
fi
DART_ROOT="$(cd "${SDK_DIR}/.." ; pwd -P)"
ANALYZER="$DART_ROOT/pkg/analyzer_cli/bin/analyzer.dart"
DEV_OPTIONS="--use-analysis-driver-memory-byte-store"
exec "$DART" "--packages=$DART_ROOT/.packages" "${EXTRA_VM_OPTIONS[@]}" "$ANALYZER" "$DEV_OPTIONS" "$SDK_ARG" "$@"

View file

@ -0,0 +1,70 @@
@echo off
REM Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
REM for details. All rights reserved. Use of this source code is governed by a
REM BSD-style license that can be found in the LICENSE file.
setlocal
rem Handle the case where dart-sdk/bin has been symlinked to.
set DIR_NAME_WITH_SLASH=%~dp0
set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
rem Get rid of surrounding quotes.
for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
set DART=%BIN_DIR%\dart
rem Get absolute full name for SDK_DIR.
for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
rem Remove trailing backslash if there is one
if %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
set SDK_ARG=--dart-sdk=%SDK_DIR%
set EXTRA_VM_OPTIONS=
if _%DARTANALYZER_DEVELOPER_MODE%_ == _1_ (
set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% --enable_asserts
)
rem We allow extra vm options to be passed in through an environment variable.
if not "_%DART_VM_OPTIONS%_" == "__" (
set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% %DART_VM_OPTIONS%
)
rem Get absolute full name for DART_ROOT.
for %%i in ("%SDK_DIR%\..\") do set DART_ROOT=%%~fi
rem Remove trailing backslash if there is one
if %DART_ROOT:~-1%==\ set DART_ROOT=%DART_ROOT:~0,-1%
set ANALYZER=%DART_ROOT%\pkg\analyzer_cli\bin\analyzer.dart
"%DART%" "--packages=%DART_ROOT%\.packages" %EXTRA_VM_OPTIONS% "%ANALYZER%" "%SDK_ARG%" %*
endlocal
exit /b %errorlevel%
rem Follow the symbolic links (junctions points) using `dir to determine the
rem canonical path. Output with a link looks something like this
rem
rem 01/03/2013 10:11 PM <JUNCTION> abc def
rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
rem
rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
rem surrounded by right angle bracket and left square bracket. Once we get
rem the filename, which is name of the link, we recursively follow that.
:follow_links
setlocal
for %%i in (%1) do set result=%%~fi
set current=
for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
^| %SystemRoot%\System32\find.exe "> %~n1 [" 2^>nul`) do (
set current=%%i
)
if not "%current%"=="" call :follow_links "%current%", result
endlocal & set %~2=%result%
goto :eof
:end

View file

@ -0,0 +1,6 @@
#!/usr/bin/env bash
# Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
. ${BASH_SOURCE%_developer}

View file

@ -0,0 +1,10 @@
@echo off
REM Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
REM for details. All rights reserved. Use of this source code is governed by a
REM BSD-style license that can be found in the LICENSE file.
setlocal
set DARTANALYZER_DEVELOPER_MODE=1
call "%~dp0dartanalyzer.bat" %*
endlocal
exit /b %errorlevel%

31
sdk_nnbd/bin/dartanalyzer_sdk Executable file
View file

@ -0,0 +1,31 @@
#!/usr/bin/env bash
# Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
# Run dartanalyzer.dart on the Dart VM. This script assumes the Dart SDK's
# directory structure.
function follow_links() {
file="$1"
while [ -h "$file" ]; do
# On Mac OS, readlink -f doesn't work.
file="$(readlink "$file")"
done
echo "$file"
}
# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
PROG_NAME="$(follow_links "$BASH_SOURCE")"
# Handle the case where dart-sdk/bin has been symlinked to.
BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
SDK_ARG="--dart-sdk=$SDK_DIR"
SNAPSHOT="$BIN_DIR/snapshots/dartanalyzer.dart.snapshot"
# We are running the snapshot in the built SDK.
DART="$BIN_DIR/dart"
exec "$DART" "$SNAPSHOT" "$SDK_ARG" "$@"

View file

@ -0,0 +1,52 @@
@echo off
REM Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
REM for details. All rights reserved. Use of this source code is governed by a
REM BSD-style license that can be found in the LICENSE file.
setlocal
rem Handle the case where dart-sdk/bin has been symlinked to.
set DIR_NAME_WITH_SLASH=%~dp0
set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
rem Get rid of surrounding quotes.
for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
set DART=%BIN_DIR%\dart
set SNAPSHOT=%BIN_DIR%\snapshots\dartanalyzer.dart.snapshot
rem Get absolute full name for SDK_DIR.
for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
rem Remove trailing backslash if there is one
if %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
set SDK_ARG=--dart-sdk=%SDK_DIR%
"%DART%" "%SNAPSHOT%" "%SDK_ARG%" %*
endlocal
exit /b %errorlevel%
rem Follow the symbolic links (junctions points) using `dir to determine the
rem canonical path. Output with a link looks something like this
rem
rem 01/03/2013 10:11 PM <JUNCTION> abc def
rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
rem
rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
rem surrounded by right angle bracket and left square bracket. Once we get
rem the filename, which is name of the link, we recursively follow that.
:follow_links
setlocal
for %%i in (%1) do set result=%%~fi
set current=
for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
^| find "> %~n1 [" 2^>nul`) do (
set current=%%i
)
if not "%current%"=="" call :follow_links "%current%", result
endlocal & set %~2=%result%
goto :eof
:end

48
sdk_nnbd/bin/dartdevc Executable file
View file

@ -0,0 +1,48 @@
#!/usr/bin/env bash
# Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
# Run dev compiler on the Dart VM. This script assumes the Dart repo's
# directory structure.
function follow_links() {
file="$1"
while [ -h "$file" ]; do
# On Mac OS, readlink -f doesn't work.
file="$(readlink "$file")"
done
echo "$file"
}
# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
PROG_NAME="$(follow_links "$BASH_SOURCE")"
# Handle the case where dart-sdk/bin has been symlinked to.
BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
SDK_ARG="--dart-sdk=$SDK_DIR"
DART="$BIN_DIR/dart"
unset EXTRA_VM_OPTIONS
declare -a EXTRA_VM_OPTIONS
case $0 in
*_developer)
EXTRA_VM_OPTIONS+=('--checked')
;;
esac
# We allow extra vm options to be passed in through an environment variable.
if [[ $DART_VM_OPTIONS ]]; then
read -a OPTIONS <<< "$DART_VM_OPTIONS"
EXTRA_VM_OPTIONS+=("${OPTIONS[@]}")
fi
DART_ROOT="$(cd "${SDK_DIR}/.." ; pwd -P)"
DEV_COMPILER="$DART_ROOT/pkg/dev_compiler/bin/dartdevc.dart"
exec "$DART" "--packages=$DART_ROOT/.packages" "${EXTRA_VM_OPTIONS[@]}" "$DEV_COMPILER" "$SDK_ARG" "$@"

66
sdk_nnbd/bin/dartdevc.bat Normal file
View file

@ -0,0 +1,66 @@
@echo off
REM Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
REM for details. All rights reserved. Use of this source code is governed by a
REM BSD-style license that can be found in the LICENSE file.
setlocal
rem Handle the case where dart-sdk/bin has been symlinked to.
set DIR_NAME_WITH_SLASH=%~dp0
set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
rem Get rid of surrounding quotes.
for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
set DART=%BIN_DIR%\dart
rem Get absolute full name for SDK_DIR.
for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
rem Remove trailing backslash if there is one
if %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
set SDK_ARG=--dart-sdk=%SDK_DIR%
set EXTRA_VM_OPTIONS=
rem We allow extra vm options to be passed in through an environment variable.
if not "_%DART_VM_OPTIONS%_" == "__" (
set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% %DART_VM_OPTIONS%
)
rem Get absolute full name for DART_ROOT.
for %%i in ("%SDK_DIR%\..\") do set DART_ROOT=%%~fi
rem Remove trailing backslash if there is one
if %DART_ROOT:~-1%==\ set DART_ROOT=%DART_ROOT:~0,-1%
set DEV_COMPILER=%DART_ROOT%\third_party\pkg\dev_compiler\bin\dartdevc.dart
"%DART%" "--packages=%DART_ROOT%\.packages" %EXTRA_VM_OPTIONS% "DEV_COMPILER%" "%SDK_ARG%" %*
endlocal
exit /b %errorlevel%
rem Follow the symbolic links (junctions points) using `dir to determine the
rem canonical path. Output with a link looks something like this
rem
rem 01/03/2013 10:11 PM <JUNCTION> abc def
rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
rem
rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
rem surrounded by right angle bracket and left square bracket. Once we get
rem the filename, which is name of the link, we recursively follow that.
:follow_links
setlocal
for %%i in (%1) do set result=%%~fi
set current=
for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
^| find "> %~n1 [" 2^>nul`) do (
set current=%%i
)
if not "%current%"=="" call :follow_links "%current%", result
endlocal & set %~2=%result%
goto :eof
:end

28
sdk_nnbd/bin/dartdevc_sdk Executable file
View file

@ -0,0 +1,28 @@
#!/usr/bin/env bash
# Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
# Run dev compiler on the Dart VM. This script assumes the Dart SDK's
# directory structure.
function follow_links() {
file="$1"
while [ -h "$file" ]; do
# On Mac OS, readlink -f doesn't work.
file="$(readlink "$file")"
done
echo "$file"
}
# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
PROG_NAME="$(follow_links "$BASH_SOURCE")"
# Handle the case where dart-sdk/bin has been symlinked to.
BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
SNAPSHOT="$BIN_DIR/snapshots/dartdevc.dart.snapshot"
# We are running the snapshot in the built SDK.
DART="$BIN_DIR/dart"
exec "$DART" "$SNAPSHOT" "$@"

View file

@ -0,0 +1,52 @@
@echo off
REM Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
REM for details. All rights reserved. Use of this source code is governed by a
REM BSD-style license that can be found in the LICENSE file.
setlocal
rem Handle the case where dart-sdk/bin has been symlinked to.
set DIR_NAME_WITH_SLASH=%~dp0
set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
rem Get rid of surrounding quotes.
for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
set DART=%BIN_DIR%\dart
set SNAPSHOT=%BIN_DIR%\snapshots\dartdevc.dart.snapshot
rem Get absolute full name for SDK_DIR.
for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
rem Remove trailing backslash if there is one
if %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
set SDK_ARG=--dart-sdk=%SDK_DIR%
"%DART%" "%SNAPSHOT%" "%SDK_ARG%" %*
endlocal
exit /b %errorlevel%
rem Follow the symbolic links (junctions points) using `dir to determine the
rem canonical path. Output with a link looks something like this
rem
rem 01/03/2013 10:11 PM <JUNCTION> abc def
rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
rem
rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
rem surrounded by right angle bracket and left square bracket. Once we get
rem the filename, which is name of the link, we recursively follow that.
:follow_links
setlocal
for %%i in (%1) do set result=%%~fi
set current=
for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
^| find "> %~n1 ["`) do (
set current=%%i
)
if not "%current%"=="" call :follow_links "%current%", result
endlocal & set %~2=%result%
goto :eof
:end

26
sdk_nnbd/bin/dartdoc Executable file
View file

@ -0,0 +1,26 @@
#!/usr/bin/env bash
# Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
function follow_links() {
file="$1"
while [ -h "$file" ]; do
# On Mac OS, readlink -f doesn't work.
file="$(readlink "$file")"
done
echo "$file"
}
# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
PROG_NAME="$(follow_links "$BASH_SOURCE")"
# Handle the case where dart-sdk/bin has been symlinked to.
BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
SNAPSHOT="$BIN_DIR/snapshots/dartdoc.dart.snapshot"
# We are running the snapshot in the built SDK.
DART="$BIN_DIR/dart"
exec "$DART" "--packages=$BIN_DIR/resources/dartdoc/.packages" "$SNAPSHOT" "$@"

44
sdk_nnbd/bin/dartdoc.bat Normal file
View file

@ -0,0 +1,44 @@
@echo off
REM Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
REM for details. All rights reserved. Use of this source code is governed by a
REM BSD-style license that can be found in the LICENSE file.
setlocal
rem Handle the case where dart-sdk/bin has been symlinked to.
set DIR_NAME_WITH_SLASH=%~dp0
set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
rem Get rid of surrounding quotes.
for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
set DART=%BIN_DIR%\dart
set SNAPSHOT=%BIN_DIR%\snapshots\dartdoc.dart.snapshot
"%DART%" "--packages=%BIN_DIR%/resources/dartdoc/.packages" "%SNAPSHOT%" %*
endlocal
exit /b %errorlevel%
rem Follow the symbolic links (junctions points) using `dir to determine the
rem canonical path. Output with a link looks something like this
rem
rem 01/03/2013 10:11 PM <JUNCTION> abc def
rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
rem
rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
rem surrounded by right angle bracket and left square bracket. Once we get
rem the filename, which is name of the link, we recursively follow that.
:follow_links
setlocal
for %%i in (%1) do set result=%%~fi
set current=
for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
^| %SystemRoot%\System32\find.exe "> %~n1 [" 2^>nul`) do (
set current=%%i
)
if not "%current%"=="" call :follow_links "%current%", result
endlocal & set %~2=%result%
goto :eof
:end

31
sdk_nnbd/bin/dartfmt Executable file
View file

@ -0,0 +1,31 @@
#!/usr/bin/env bash
# Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
# Run dart_style/bin/format.dart on the Dart VM. This script assumes the Dart
# repo's directory structure.
function follow_links() {
file="$1"
while [ -h "$file" ]; do
# On Mac OS, readlink -f doesn't work.
file="$(readlink "$file")"
done
echo "$file"
}
# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
PROG_NAME="$(follow_links "$BASH_SOURCE")"
# Handle the case where dart-sdk/bin has been symlinked to.
BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
DART="$BIN_DIR/dart"
DART_ROOT="$(cd "${SDK_DIR}/.." ; pwd -P)"
DARTFMT="$DART_ROOT/third_party/pkg_tested/dart_style/bin/format.dart"
exec "$DART" "--packages=$DART_ROOT/.packages" "$DARTFMT" "$@"

57
sdk_nnbd/bin/dartfmt.bat Normal file
View file

@ -0,0 +1,57 @@
@echo off
REM Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
REM for details. All rights reserved. Use of this source code is governed by a
REM BSD-style license that can be found in the LICENSE file.
setlocal
rem Handle the case where dart-sdk/bin has been symlinked to.
set DIR_NAME_WITH_SLASH=%~dp0
set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
rem Get rid of surrounding quotes.
for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
set DART=%BIN_DIR%\dart
rem Get absolute full name for SDK_DIR.
for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
rem Remove trailing backslash if there is one
if %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
rem Get absolute full name for DART_ROOT.
for %%i in ("%SDK_DIR%\..\") do set DART_ROOT=%%~fi
rem Remove trailing backslash if there is one
if %DART_ROOT:~-1%==\ set DART_ROOT=%DART_ROOT:~0,-1%
set DARTFMT=%DART_ROOT%\third_party\pkg_tested\dart_style\bin\format.dart
"%DART%" "--packages=%DART_ROOT%\.packages" "%DARTFMT%" %*
endlocal
exit /b %errorlevel%
rem Follow the symbolic links (junctions points) using `dir to determine the
rem canonical path. Output with a link looks something like this
rem
rem 01/03/2013 10:11 PM <JUNCTION> abc def
rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
rem
rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
rem surrounded by right angle bracket and left square bracket. Once we get
rem the filename, which is name of the link, we recursively follow that.
:follow_links
setlocal
for %%i in (%1) do set result=%%~fi
set current=
for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
^| %SystemRoot%\System32\find.exe "> %~n1 [" 2^>nul`) do (
set current=%%i
)
if not "%current%"=="" call :follow_links "%current%", result
endlocal & set %~2=%result%
goto :eof
:end

29
sdk_nnbd/bin/dartfmt_sdk Executable file
View file

@ -0,0 +1,29 @@
#!/usr/bin/env bash
# Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
# Run dart_style/bin/format.dart on the Dart VM. This script assumes the Dart
# SDK's directory structure.
function follow_links() {
file="$1"
while [ -h "$file" ]; do
# On Mac OS, readlink -f doesn't work.
file="$(readlink "$file")"
done
echo "$file"
}
# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
PROG_NAME="$(follow_links "$BASH_SOURCE")"
# Handle the case where dart-sdk/bin has been symlinked to.
BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
SNAPSHOT="$BIN_DIR/snapshots/dartfmt.dart.snapshot"
# We are running the snapshot in the built SDK.
DART="$BIN_DIR/dart"
exec "$DART" "$SNAPSHOT" "$@"

View file

@ -0,0 +1,44 @@
@echo off
REM Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
REM for details. All rights reserved. Use of this source code is governed by a
REM BSD-style license that can be found in the LICENSE file.
setlocal
rem Handle the case where dart-sdk/bin has been symlinked to.
set DIR_NAME_WITH_SLASH=%~dp0
set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
rem Get rid of surrounding quotes.
for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
set DART=%BIN_DIR%\dart
set SNAPSHOT=%BIN_DIR%\snapshots\dartfmt.dart.snapshot
"%DART%" "%SNAPSHOT%" %*
endlocal
exit /b %errorlevel%
rem Follow the symbolic links (junctions points) using `dir to determine the
rem canonical path. Output with a link looks something like this
rem
rem 01/03/2013 10:11 PM <JUNCTION> abc def
rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
rem
rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
rem surrounded by right angle bracket and left square bracket. Once we get
rem the filename, which is name of the link, we recursively follow that.
:follow_links
setlocal
for %%i in (%1) do set result=%%~fi
set current=
for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
^| find "> %~n1 ["`) do (
set current=%%i
)
if not "%current%"=="" call :follow_links "%current%", result
endlocal & set %~2=%result%
goto :eof
:end

85
sdk_nnbd/bin/pub Executable file
View file

@ -0,0 +1,85 @@
#!/usr/bin/env bash
# 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.
# Run pub.dart on the Dart VM. This script is only used when running pub from
# within the Dart source repo. The shipped SDK instead uses "pub_sdk", which is
# renamed to "pub" when the SDK is built.
function follow_links() {
file="$1"
while [ -h "$file" ]; do
# On Mac OS, readlink -f doesn't work.
file="$(readlink "$file")"
done
echo "$file"
}
# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
PROG_NAME="$(follow_links "$BASH_SOURCE")"
# Handle the case where dart-sdk/bin has been symlinked to.
BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
SNAPSHOT="$BIN_DIR/snapshots/pub.dart.snapshot"
unset VM_OPTIONS
declare -a VM_OPTIONS
if [[ `uname` == 'Darwin' ]];
then
OUT_DIR="$BIN_DIR"/../../xcodebuild/
else
OUT_DIR="$BIN_DIR"/../../out/
fi
# Allow extra VM options to be passed in through an environment variable.
if [[ $DART_VM_OPTIONS ]]; then
read -a OPTIONS <<< "$DART_VM_OPTIONS"
VM_OPTIONS+=("${OPTIONS[@]}")
fi
if [ -z "$DART_CONFIGURATION" ];
then
DIRS=$( ls "$OUT_DIR" )
# list of possible configurations in decreasing desirability
CONFIGS=("ReleaseX64" "ReleaseIA32" "DebugX64" "DebugIA32"
"ReleaseARM" "ReleaseARM64" "ReleaseARMV5TE"
"DebugARM" "DebugARM64" "DebugARMV5TE")
DART_CONFIGURATION="None"
for CONFIG in ${CONFIGS[*]}
do
for DIR in $DIRS;
do
if [ "$CONFIG" = "$DIR" ];
then
# choose most desirable configuration that is available and break
DART_CONFIGURATION="$DIR"
break 2
fi
done
done
if [ "$DART_CONFIGURATION" = "None" ]
then
echo "No valid dart configuration found in $OUT_DIR"
exit 1
fi
fi
if [[ `uname` == 'Darwin' ]];
then
BUILD_DIR="$SDK_DIR/../xcodebuild/$DART_CONFIGURATION"
else
BUILD_DIR="$SDK_DIR/../out/$DART_CONFIGURATION"
fi
# Use the Dart binary in the built SDK so pub can find the version file next
# to it.
DART="$BUILD_DIR/dart-sdk/bin/dart"
# Run pub.
PUB="$SDK_DIR/../third_party/pkg/pub/bin/pub.dart"
exec "$DART" "--packages=$SDK_DIR/../.packages" "${VM_OPTIONS[@]}" "$PUB" "$@"

56
sdk_nnbd/bin/pub.bat Normal file
View file

@ -0,0 +1,56 @@
@echo off
REM Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
REM for details. All rights reserved. Use of this source code is governed by a
REM BSD-style license that can be found in the LICENSE file.
rem Run pub.dart on the Dart VM. This script is only used when running pub from
rem within the Dart source repo. The shipped SDK instead uses "pub_sdk.bat",
rem which is renamed to "pub.bat" when the SDK is built.
setlocal
rem Handle the case where dart-sdk/bin has been symlinked to.
set DIR_NAME_WITH_SLASH=%~dp0
set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
rem Get rid of surrounding quotes.
for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
rem Get absolute full name for SDK_DIR.
for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
rem Remove trailing backslash if there is one
IF %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
set VM_OPTIONS=
rem We allow extra vm options to be passed in through an environment variable.
if not "_%DART_VM_OPTIONS%_" == "__" (
set VM_OPTIONS=%VM_OPTIONS% %DART_VM_OPTIONS%
)
rem Use the Dart binary in the built SDK so pub can find the version file next
rem to it.
set BUILD_DIR=%SDK_DIR%\..\out\ReleaseX64
set DART=%BUILD_DIR%\dart-sdk\bin\dart
rem Run pub.
set PUB="%SDK_DIR%\..\third_party\pkg\pub\bin\pub.dart"
"%DART%" "--packages=%SDK_DIR%\..\.packages" %VM_OPTIONS% "%PUB%" %*
endlocal
exit /b %errorlevel%
:follow_links
setlocal
for %%i in (%1) do set result=%%~fi
set current=
for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
^| %SystemRoot%\System32\find.exe "> %~n1 [" 2^>nul`) do (
set current=%%i
)
if not "%current%"=="" call :follow_links "%current%", result
endlocal & set %~2=%result%
goto :eof
:end

50
sdk_nnbd/bin/pub_sdk Executable file
View file

@ -0,0 +1,50 @@
#!/usr/bin/env bash
# Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
# Run pub.dart on the Dart VM. This script assumes the Dart SDK's directory
# structure.
function follow_links() {
file="$1"
while [ -h "$file" ]; do
# On Mac OS, readlink -f doesn't work.
file="$(readlink "$file")"
done
echo "$file"
}
function array_contains() {
local needle="$1"
local element
shift
for element; do [ "$element" = "$needle" ] && return 0; done
return 1
}
# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
PROG_NAME="$(follow_links "$BASH_SOURCE")"
# Handle the case where dart-sdk/bin has been symlinked to.
BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
unset VM_OPTIONS
declare -a VM_OPTIONS
# Allow extra VM options to be passed in through an environment variable.
if [[ $DART_VM_OPTIONS ]]; then
read -a OPTIONS <<< "$DART_VM_OPTIONS"
VM_OPTIONS+=("${OPTIONS[@]}")
fi
# Run the pub snapshot.
DART="$BIN_DIR/dart"
if array_contains "--no-preview-dart-2" "${VM_OPTIONS[@]}"; then
echo "Pub no longer supports Dart 1"
exit -1
else
SNAPSHOT="$BIN_DIR/snapshots/pub.dart.snapshot"
exec "$DART" "${VM_OPTIONS[@]}" "$SNAPSHOT" "$@"
fi

53
sdk_nnbd/bin/pub_sdk.bat Normal file
View file

@ -0,0 +1,53 @@
@echo off
REM Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
REM for details. All rights reserved. Use of this source code is governed by a
REM BSD-style license that can be found in the LICENSE file.
setlocal
rem Handle the case where dart-sdk/bin has been symlinked to.
set DIR_NAME_WITH_SLASH=%~dp0
set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
rem Get rid of surrounding quotes.
for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
rem Get absolute full name for SDK_DIR.
for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
rem Remove trailing backslash if there is one
IF %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
set VM_OPTIONS=
set USING_DART_1=
rem We allow extra vm options to be passed in through an environment variable.
if not "_%DART_VM_OPTIONS%_" == "__" (
set VM_OPTIONS=%VM_OPTIONS% %DART_VM_OPTIONS%
for %%o in (%DART_VM_OPTIONS%) do (
if "%%o" equ "--no-preview-dart-2" set USING_DART_1=y
)
)
if defined USING_DART_1 (
echo "Pub no longer supports Dart 1"
) else (
"%BIN_DIR%\dart" %VM_OPTIONS% "%BIN_DIR%\snapshots\pub.dart.snapshot" %*
)
endlocal
exit /b %errorlevel%
:follow_links
setlocal
for %%i in (%1) do set result=%%~fi
set current=
for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
^| find "> %~n1 [" 2^>nul`) do (
set current=%%i
)
if not "%current%"=="" call :follow_links "%current%", result
endlocal & set %~2=%result%
goto :eof
:end

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,458 @@
// 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.
part of dart._http;
class _CryptoUtils {
static const int PAD = 61; // '='
static const int CR = 13; // '\r'
static const int LF = 10; // '\n'
static const int LINE_LENGTH = 76;
static const String _encodeTable =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const String _encodeTableUrlSafe =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
// Lookup table used for finding Base 64 alphabet index of a given byte.
// -2 : Outside Base 64 alphabet.
// -1 : '\r' or '\n'
// 0 : = (Padding character).
// >0 : Base 64 alphabet index of given byte.
static const List<int> _decodeTable = const [
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -2, -2, -1, -2, -2, //
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, //
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, 62, -2, 63, //
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -2, -2, -2, 00, -2, -2, //
-2, 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, //
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -2, -2, -2, -2, 63, //
-2, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, //
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -2, -2, -2, -2, -2, //
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, //
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, //
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, //
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, //
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, //
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, //
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, //
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2
];
static Random _rng = new Random.secure();
static Uint8List getRandomBytes(int count) {
final Uint8List result = new Uint8List(count);
for (int i = 0; i < count; i++) {
result[i] = _rng.nextInt(0xff);
}
return result;
}
static String bytesToHex(List<int> bytes) {
var result = new StringBuffer();
for (var part in bytes) {
result.write('${part < 16 ? '0' : ''}${part.toRadixString(16)}');
}
return result.toString();
}
static String bytesToBase64(List<int> bytes,
[bool urlSafe = false, bool addLineSeparator = false]) {
int len = bytes.length;
if (len == 0) {
return "";
}
final String lookup = urlSafe ? _encodeTableUrlSafe : _encodeTable;
// Size of 24 bit chunks.
final int remainderLength = len.remainder(3);
final int chunkLength = len - remainderLength;
// Size of base output.
int outputLen = ((len ~/ 3) * 4) + ((remainderLength > 0) ? 4 : 0);
// Add extra for line separators.
if (addLineSeparator) {
outputLen += ((outputLen - 1) ~/ LINE_LENGTH) << 1;
}
List<int> out = new List<int>(outputLen);
// Encode 24 bit chunks.
int j = 0, i = 0, c = 0;
while (i < chunkLength) {
int x = ((bytes[i++] << 16) & 0xFFFFFF) |
((bytes[i++] << 8) & 0xFFFFFF) |
bytes[i++];
out[j++] = lookup.codeUnitAt(x >> 18);
out[j++] = lookup.codeUnitAt((x >> 12) & 0x3F);
out[j++] = lookup.codeUnitAt((x >> 6) & 0x3F);
out[j++] = lookup.codeUnitAt(x & 0x3f);
// Add optional line separator for each 76 char output.
if (addLineSeparator && ++c == 19 && j < outputLen - 2) {
out[j++] = CR;
out[j++] = LF;
c = 0;
}
}
// If input length if not a multiple of 3, encode remaining bytes and
// add padding.
if (remainderLength == 1) {
int x = bytes[i];
out[j++] = lookup.codeUnitAt(x >> 2);
out[j++] = lookup.codeUnitAt((x << 4) & 0x3F);
out[j++] = PAD;
out[j++] = PAD;
} else if (remainderLength == 2) {
int x = bytes[i];
int y = bytes[i + 1];
out[j++] = lookup.codeUnitAt(x >> 2);
out[j++] = lookup.codeUnitAt(((x << 4) | (y >> 4)) & 0x3F);
out[j++] = lookup.codeUnitAt((y << 2) & 0x3F);
out[j++] = PAD;
}
return new String.fromCharCodes(out);
}
static List<int> base64StringToBytes(String input,
[bool ignoreInvalidCharacters = true]) {
int len = input.length;
if (len == 0) {
return new List<int>(0);
}
// Count '\r', '\n' and illegal characters, For illegal characters,
// if [ignoreInvalidCharacters] is false, throw an exception.
int extrasLen = 0;
for (int i = 0; i < len; i++) {
int c = _decodeTable[input.codeUnitAt(i)];
if (c < 0) {
extrasLen++;
if (c == -2 && !ignoreInvalidCharacters) {
throw new FormatException('Invalid character: ${input[i]}');
}
}
}
if ((len - extrasLen) % 4 != 0) {
throw new FormatException('''Size of Base 64 characters in Input
must be a multiple of 4. Input: $input''');
}
// Count pad characters, ignore illegal characters at the end.
int padLength = 0;
for (int i = len - 1; i >= 0; i--) {
int currentCodeUnit = input.codeUnitAt(i);
if (_decodeTable[currentCodeUnit] > 0) break;
if (currentCodeUnit == PAD) padLength++;
}
int outputLen = (((len - extrasLen) * 6) >> 3) - padLength;
List<int> out = new List<int>(outputLen);
for (int i = 0, o = 0; o < outputLen;) {
// Accumulate 4 valid 6 bit Base 64 characters into an int.
int x = 0;
for (int j = 4; j > 0;) {
int c = _decodeTable[input.codeUnitAt(i++)];
if (c >= 0) {
x = ((x << 6) & 0xFFFFFF) | c;
j--;
}
}
out[o++] = x >> 16;
if (o < outputLen) {
out[o++] = (x >> 8) & 0xFF;
if (o < outputLen) out[o++] = x & 0xFF;
}
}
return out;
}
}
// Constants.
const _MASK_8 = 0xff;
const _MASK_32 = 0xffffffff;
const _BITS_PER_BYTE = 8;
const _BYTES_PER_WORD = 4;
// Base class encapsulating common behavior for cryptographic hash
// functions.
abstract class _HashBase {
// Hasher state.
final int _chunkSizeInWords;
final int _digestSizeInWords;
final bool _bigEndianWords;
int _lengthInBytes = 0;
List<int> _pendingData;
List<int> _currentChunk;
List<int> _h;
bool _digestCalled = false;
_HashBase(
this._chunkSizeInWords, this._digestSizeInWords, this._bigEndianWords)
: _pendingData = [] {
_currentChunk = new List(_chunkSizeInWords);
_h = new List(_digestSizeInWords);
}
// Update the hasher with more data.
add(List<int> data) {
if (_digestCalled) {
throw new StateError(
'Hash update method called after digest was retrieved');
}
_lengthInBytes += data.length;
_pendingData.addAll(data);
_iterate();
}
// Finish the hash computation and return the digest string.
List<int> close() {
if (_digestCalled) {
return _resultAsBytes();
}
_digestCalled = true;
_finalizeData();
_iterate();
assert(_pendingData.length == 0);
return _resultAsBytes();
}
// Returns the block size of the hash in bytes.
int get blockSize {
return _chunkSizeInWords * _BYTES_PER_WORD;
}
// Create a fresh instance of this Hash.
newInstance();
// One round of the hash computation.
_updateHash(List<int> m);
// Helper methods.
_add32(x, y) => (x + y) & _MASK_32;
_roundUp(val, n) => (val + n - 1) & -n;
// Rotate left limiting to unsigned 32-bit values.
int _rotl32(int val, int shift) {
var mod_shift = shift & 31;
return ((val << mod_shift) & _MASK_32) |
((val & _MASK_32) >> (32 - mod_shift));
}
// Compute the final result as a list of bytes from the hash words.
List<int> _resultAsBytes() {
var result = <int>[];
for (var i = 0; i < _h.length; i++) {
result.addAll(_wordToBytes(_h[i]));
}
return result;
}
// Converts a list of bytes to a chunk of 32-bit words.
_bytesToChunk(List<int> data, int dataIndex) {
assert((data.length - dataIndex) >= (_chunkSizeInWords * _BYTES_PER_WORD));
for (var wordIndex = 0; wordIndex < _chunkSizeInWords; wordIndex++) {
var w3 = _bigEndianWords ? data[dataIndex] : data[dataIndex + 3];
var w2 = _bigEndianWords ? data[dataIndex + 1] : data[dataIndex + 2];
var w1 = _bigEndianWords ? data[dataIndex + 2] : data[dataIndex + 1];
var w0 = _bigEndianWords ? data[dataIndex + 3] : data[dataIndex];
dataIndex += 4;
var word = (w3 & 0xff) << 24;
word |= (w2 & _MASK_8) << 16;
word |= (w1 & _MASK_8) << 8;
word |= (w0 & _MASK_8);
_currentChunk[wordIndex] = word;
}
}
// Convert a 32-bit word to four bytes.
List<int> _wordToBytes(int word) {
List<int> bytes = new List(_BYTES_PER_WORD);
bytes[0] = (word >> (_bigEndianWords ? 24 : 0)) & _MASK_8;
bytes[1] = (word >> (_bigEndianWords ? 16 : 8)) & _MASK_8;
bytes[2] = (word >> (_bigEndianWords ? 8 : 16)) & _MASK_8;
bytes[3] = (word >> (_bigEndianWords ? 0 : 24)) & _MASK_8;
return bytes;
}
// Iterate through data updating the hash computation for each
// chunk.
_iterate() {
var len = _pendingData.length;
var chunkSizeInBytes = _chunkSizeInWords * _BYTES_PER_WORD;
if (len >= chunkSizeInBytes) {
var index = 0;
for (; (len - index) >= chunkSizeInBytes; index += chunkSizeInBytes) {
_bytesToChunk(_pendingData, index);
_updateHash(_currentChunk);
}
_pendingData = _pendingData.sublist(index, len);
}
}
// Finalize the data. Add a 1 bit to the end of the message. Expand with
// 0 bits and add the length of the message.
_finalizeData() {
_pendingData.add(0x80);
var contentsLength = _lengthInBytes + 9;
var chunkSizeInBytes = _chunkSizeInWords * _BYTES_PER_WORD;
var finalizedLength = _roundUp(contentsLength, chunkSizeInBytes);
var zeroPadding = finalizedLength - contentsLength;
for (var i = 0; i < zeroPadding; i++) {
_pendingData.add(0);
}
var lengthInBits = _lengthInBytes * _BITS_PER_BYTE;
assert(lengthInBits < pow(2, 32));
if (_bigEndianWords) {
_pendingData.addAll(_wordToBytes(0));
_pendingData.addAll(_wordToBytes(lengthInBits & _MASK_32));
} else {
_pendingData.addAll(_wordToBytes(lengthInBits & _MASK_32));
_pendingData.addAll(_wordToBytes(0));
}
}
}
// The MD5 hasher is used to compute an MD5 message digest.
class _MD5 extends _HashBase {
_MD5() : super(16, 4, false) {
_h[0] = 0x67452301;
_h[1] = 0xefcdab89;
_h[2] = 0x98badcfe;
_h[3] = 0x10325476;
}
// Returns a new instance of this Hash.
_MD5 newInstance() {
return new _MD5();
}
static const _k = const [
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, //
0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, //
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, //
0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, //
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, //
0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, //
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, //
0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, //
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, //
0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, //
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
];
static const _r = const [
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, //
20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, //
16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, //
10, 15, 21, 6, 10, 15, 21
];
// Compute one iteration of the MD5 algorithm with a chunk of
// 16 32-bit pieces.
void _updateHash(List<int> m) {
assert(m.length == 16);
var a = _h[0];
var b = _h[1];
var c = _h[2];
var d = _h[3];
var t0;
var t1;
for (var i = 0; i < 64; i++) {
if (i < 16) {
t0 = (b & c) | ((~b & _MASK_32) & d);
t1 = i;
} else if (i < 32) {
t0 = (d & b) | ((~d & _MASK_32) & c);
t1 = ((5 * i) + 1) % 16;
} else if (i < 48) {
t0 = b ^ c ^ d;
t1 = ((3 * i) + 5) % 16;
} else {
t0 = c ^ (b | (~d & _MASK_32));
t1 = (7 * i) % 16;
}
var temp = d;
d = c;
c = b;
b = _add32(
b, _rotl32(_add32(_add32(a, t0), _add32(_k[i], m[t1])), _r[i]));
a = temp;
}
_h[0] = _add32(a, _h[0]);
_h[1] = _add32(b, _h[1]);
_h[2] = _add32(c, _h[2]);
_h[3] = _add32(d, _h[3]);
}
}
// The SHA1 hasher is used to compute an SHA1 message digest.
class _SHA1 extends _HashBase {
// Construct a SHA1 hasher object.
_SHA1()
: _w = new List(80),
super(16, 5, true) {
_h[0] = 0x67452301;
_h[1] = 0xEFCDAB89;
_h[2] = 0x98BADCFE;
_h[3] = 0x10325476;
_h[4] = 0xC3D2E1F0;
}
// Returns a new instance of this Hash.
_SHA1 newInstance() {
return new _SHA1();
}
// Compute one iteration of the SHA1 algorithm with a chunk of
// 16 32-bit pieces.
void _updateHash(List<int> m) {
assert(m.length == 16);
var a = _h[0];
var b = _h[1];
var c = _h[2];
var d = _h[3];
var e = _h[4];
for (var i = 0; i < 80; i++) {
if (i < 16) {
_w[i] = m[i];
} else {
var n = _w[i - 3] ^ _w[i - 8] ^ _w[i - 14] ^ _w[i - 16];
_w[i] = _rotl32(n, 1);
}
var t = _add32(_add32(_rotl32(a, 5), e), _w[i]);
if (i < 20) {
t = _add32(_add32(t, (b & c) | (~b & d)), 0x5A827999);
} else if (i < 40) {
t = _add32(_add32(t, (b ^ c ^ d)), 0x6ED9EBA1);
} else if (i < 60) {
t = _add32(_add32(t, (b & c) | (b & d) | (c & d)), 0x8F1BBCDC);
} else {
t = _add32(_add32(t, b ^ c ^ d), 0xCA62C1D6);
}
e = d;
d = c;
c = _rotl32(b, 30);
b = a;
a = t & _MASK_32;
}
_h[0] = _add32(a, _h[0]);
_h[1] = _add32(b, _h[1]);
_h[2] = _add32(c, _h[2]);
_h[3] = _add32(d, _h[3]);
_h[4] = _add32(e, _h[4]);
}
List<int> _w;
}

2196
sdk_nnbd/lib/_http/http.dart Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,388 @@
// 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.
part of dart._http;
/**
* Utility functions for working with dates with HTTP specific date
* formats.
*/
class HttpDate {
// From RFC-2616 section "3.3.1 Full Date",
// http://tools.ietf.org/html/rfc2616#section-3.3.1
//
// HTTP-date = rfc1123-date | rfc850-date | asctime-date
// rfc1123-date = wkday "," SP date1 SP time SP "GMT"
// rfc850-date = weekday "," SP date2 SP time SP "GMT"
// asctime-date = wkday SP date3 SP time SP 4DIGIT
// date1 = 2DIGIT SP month SP 4DIGIT
// ; day month year (e.g., 02 Jun 1982)
// date2 = 2DIGIT "-" month "-" 2DIGIT
// ; day-month-year (e.g., 02-Jun-82)
// date3 = month SP ( 2DIGIT | ( SP 1DIGIT ))
// ; month day (e.g., Jun 2)
// time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
// ; 00:00:00 - 23:59:59
// wkday = "Mon" | "Tue" | "Wed"
// | "Thu" | "Fri" | "Sat" | "Sun"
// weekday = "Monday" | "Tuesday" | "Wednesday"
// | "Thursday" | "Friday" | "Saturday" | "Sunday"
// month = "Jan" | "Feb" | "Mar" | "Apr"
// | "May" | "Jun" | "Jul" | "Aug"
// | "Sep" | "Oct" | "Nov" | "Dec"
/**
* Format a date according to
* [RFC-1123](http://tools.ietf.org/html/rfc1123 "RFC-1123"),
* e.g. `Thu, 1 Jan 1970 00:00:00 GMT`.
*/
static String format(DateTime date) {
const List wkday = const ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
const List month = const [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
];
DateTime d = date.toUtc();
StringBuffer sb = new StringBuffer()
..write(wkday[d.weekday - 1])
..write(", ")
..write(d.day <= 9 ? "0" : "")
..write(d.day.toString())
..write(" ")
..write(month[d.month - 1])
..write(" ")
..write(d.year.toString())
..write(d.hour <= 9 ? " 0" : " ")
..write(d.hour.toString())
..write(d.minute <= 9 ? ":0" : ":")
..write(d.minute.toString())
..write(d.second <= 9 ? ":0" : ":")
..write(d.second.toString())
..write(" GMT");
return sb.toString();
}
/**
* Parse a date string in either of the formats
* [RFC-1123](http://tools.ietf.org/html/rfc1123 "RFC-1123"),
* [RFC-850](http://tools.ietf.org/html/rfc850 "RFC-850") or
* ANSI C's asctime() format. These formats are listed here.
*
* Thu, 1 Jan 1970 00:00:00 GMT
* Thursday, 1-Jan-1970 00:00:00 GMT
* Thu Jan 1 00:00:00 1970
*
* For more information see [RFC-2616 section
* 3.1.1](http://tools.ietf.org/html/rfc2616#section-3.3.1
* "RFC-2616 section 3.1.1").
*/
static DateTime parse(String date) {
final int SP = 32;
const List wkdays = const ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
const List weekdays = const [
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday"
];
const List months = const [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
];
const List wkdaysLowerCase = const [
"mon",
"tue",
"wed",
"thu",
"fri",
"sat",
"sun"
];
const List weekdaysLowerCase = const [
"monday",
"tuesday",
"wednesday",
"thursday",
"friday",
"saturday",
"sunday"
];
const List monthsLowerCase = const [
"jan",
"feb",
"mar",
"apr",
"may",
"jun",
"jul",
"aug",
"sep",
"oct",
"nov",
"dec"
];
final int formatRfc1123 = 0;
final int formatRfc850 = 1;
final int formatAsctime = 2;
int index = 0;
String tmp;
int format;
void expect(String s) {
if (date.length - index < s.length) {
throw new HttpException("Invalid HTTP date $date");
}
String tmp = date.substring(index, index + s.length);
if (tmp != s) {
throw new HttpException("Invalid HTTP date $date");
}
index += s.length;
}
int expectWeekday() {
int weekday;
// The formatting of the weekday signals the format of the date string.
int pos = date.indexOf(",", index);
if (pos == -1) {
int pos = date.indexOf(" ", index);
if (pos == -1) throw new HttpException("Invalid HTTP date $date");
tmp = date.substring(index, pos);
index = pos + 1;
weekday = wkdays.indexOf(tmp);
if (weekday != -1) {
format = formatAsctime;
return weekday;
}
} else {
tmp = date.substring(index, pos);
index = pos + 1;
weekday = wkdays.indexOf(tmp);
if (weekday != -1) {
format = formatRfc1123;
return weekday;
}
weekday = weekdays.indexOf(tmp);
if (weekday != -1) {
format = formatRfc850;
return weekday;
}
}
throw new HttpException("Invalid HTTP date $date");
}
int expectMonth(String separator) {
int pos = date.indexOf(separator, index);
if (pos - index != 3) throw new HttpException("Invalid HTTP date $date");
tmp = date.substring(index, pos);
index = pos + 1;
int month = months.indexOf(tmp);
if (month != -1) return month;
throw new HttpException("Invalid HTTP date $date");
}
int expectNum(String separator) {
int pos;
if (separator.length > 0) {
pos = date.indexOf(separator, index);
} else {
pos = date.length;
}
String tmp = date.substring(index, pos);
index = pos + separator.length;
try {
int value = int.parse(tmp);
return value;
} on FormatException catch (e) {
throw new HttpException("Invalid HTTP date $date");
}
}
void expectEnd() {
if (index != date.length) {
throw new HttpException("Invalid HTTP date $date");
}
}
int weekday = expectWeekday();
int day;
int month;
int year;
int hours;
int minutes;
int seconds;
if (format == formatAsctime) {
month = expectMonth(" ");
if (date.codeUnitAt(index) == SP) index++;
day = expectNum(" ");
hours = expectNum(":");
minutes = expectNum(":");
seconds = expectNum(" ");
year = expectNum("");
} else {
expect(" ");
day = expectNum(format == formatRfc1123 ? " " : "-");
month = expectMonth(format == formatRfc1123 ? " " : "-");
year = expectNum(" ");
hours = expectNum(":");
minutes = expectNum(":");
seconds = expectNum(" ");
expect("GMT");
}
expectEnd();
return new DateTime.utc(year, month + 1, day, hours, minutes, seconds, 0);
}
// Parse a cookie date string.
static DateTime _parseCookieDate(String date) {
const List monthsLowerCase = const [
"jan",
"feb",
"mar",
"apr",
"may",
"jun",
"jul",
"aug",
"sep",
"oct",
"nov",
"dec"
];
int position = 0;
void error() {
throw new HttpException("Invalid cookie date $date");
}
bool isEnd() => position == date.length;
bool isDelimiter(String s) {
int char = s.codeUnitAt(0);
if (char == 0x09) return true;
if (char >= 0x20 && char <= 0x2F) return true;
if (char >= 0x3B && char <= 0x40) return true;
if (char >= 0x5B && char <= 0x60) return true;
if (char >= 0x7B && char <= 0x7E) return true;
return false;
}
bool isNonDelimiter(String s) {
int char = s.codeUnitAt(0);
if (char >= 0x00 && char <= 0x08) return true;
if (char >= 0x0A && char <= 0x1F) return true;
if (char >= 0x30 && char <= 0x39) return true; // Digit
if (char == 0x3A) return true; // ':'
if (char >= 0x41 && char <= 0x5A) return true; // Alpha
if (char >= 0x61 && char <= 0x7A) return true; // Alpha
if (char >= 0x7F && char <= 0xFF) return true; // Alpha
return false;
}
bool isDigit(String s) {
int char = s.codeUnitAt(0);
if (char > 0x2F && char < 0x3A) return true;
return false;
}
int getMonth(String month) {
if (month.length < 3) return -1;
return monthsLowerCase.indexOf(month.substring(0, 3));
}
int toInt(String s) {
int index = 0;
for (; index < s.length && isDigit(s[index]); index++);
return int.parse(s.substring(0, index));
}
var tokens = [];
while (!isEnd()) {
while (!isEnd() && isDelimiter(date[position])) position++;
int start = position;
while (!isEnd() && isNonDelimiter(date[position])) position++;
tokens.add(date.substring(start, position).toLowerCase());
while (!isEnd() && isDelimiter(date[position])) position++;
}
String timeStr;
String dayOfMonthStr;
String monthStr;
String yearStr;
for (var token in tokens) {
if (token.length < 1) continue;
if (timeStr == null &&
token.length >= 5 &&
isDigit(token[0]) &&
(token[1] == ":" || (isDigit(token[1]) && token[2] == ":"))) {
timeStr = token;
} else if (dayOfMonthStr == null && isDigit(token[0])) {
dayOfMonthStr = token;
} else if (monthStr == null && getMonth(token) >= 0) {
monthStr = token;
} else if (yearStr == null &&
token.length >= 2 &&
isDigit(token[0]) &&
isDigit(token[1])) {
yearStr = token;
}
}
if (timeStr == null ||
dayOfMonthStr == null ||
monthStr == null ||
yearStr == null) {
error();
}
int year = toInt(yearStr);
if (year >= 70 && year <= 99)
year += 1900;
else if (year >= 0 && year <= 69) year += 2000;
if (year < 1601) error();
int dayOfMonth = toInt(dayOfMonthStr);
if (dayOfMonth < 1 || dayOfMonth > 31) error();
int month = getMonth(monthStr) + 1;
var timeList = timeStr.split(":");
if (timeList.length != 3) error();
int hour = toInt(timeList[0]);
int minute = toInt(timeList[1]);
int second = toInt(timeList[2]);
if (hour > 23) error();
if (minute > 59) error();
if (second > 59) error();
return new DateTime.utc(year, month, dayOfMonth, hour, minute, second, 0);
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,205 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart._http;
const String _DART_SESSION_ID = "DARTSESSID";
// A _HttpSession is a node in a double-linked list, with _next and _prev being
// the previous and next pointers.
class _HttpSession implements HttpSession {
// Destroyed marked. Used by the http connection to see if a session is valid.
bool _destroyed = false;
bool _isNew = true;
DateTime _lastSeen;
Function _timeoutCallback;
_HttpSessionManager _sessionManager;
// Pointers in timeout queue.
_HttpSession _prev;
_HttpSession _next;
final String id;
final Map _data = new HashMap();
_HttpSession(this._sessionManager, this.id) : _lastSeen = new DateTime.now();
void destroy() {
_destroyed = true;
_sessionManager._removeFromTimeoutQueue(this);
_sessionManager._sessions.remove(id);
}
// Mark the session as seen. This will reset the timeout and move the node to
// the end of the timeout queue.
void _markSeen() {
_lastSeen = new DateTime.now();
_sessionManager._bumpToEnd(this);
}
DateTime get lastSeen => _lastSeen;
bool get isNew => _isNew;
void set onTimeout(void callback()) {
_timeoutCallback = callback;
}
// Map implementation:
bool containsValue(value) => _data.containsValue(value);
bool containsKey(key) => _data.containsKey(key);
operator [](key) => _data[key];
void operator []=(key, value) {
_data[key] = value;
}
putIfAbsent(key, ifAbsent) => _data.putIfAbsent(key, ifAbsent);
addAll(Map other) => _data.addAll(other);
remove(key) => _data.remove(key);
void clear() {
_data.clear();
}
void forEach(void f(key, value)) {
_data.forEach(f);
}
Iterable<MapEntry> get entries => _data.entries;
void addEntries(Iterable<MapEntry> entries) {
_data.addEntries(entries);
}
Map<K, V> map<K, V>(MapEntry<K, V> transform(key, value)) =>
_data.map(transform);
void removeWhere(bool test(key, value)) {
_data.removeWhere(test);
}
Map<K, V> cast<K, V>() => _data.cast<K, V>();
update(key, update(value), {ifAbsent()}) =>
_data.update(key, update, ifAbsent: ifAbsent);
void updateAll(update(key, value)) {
_data.updateAll(update);
}
Iterable get keys => _data.keys;
Iterable get values => _data.values;
int get length => _data.length;
bool get isEmpty => _data.isEmpty;
bool get isNotEmpty => _data.isNotEmpty;
String toString() => 'HttpSession id:$id $_data';
}
// Private class used to manage all the active sessions. The sessions are stored
// in two ways:
//
// * In a map, mapping from ID to HttpSession.
// * In a linked list, used as a timeout queue.
class _HttpSessionManager {
Map<String, _HttpSession> _sessions;
int _sessionTimeout = 20 * 60; // 20 mins.
_HttpSession _head;
_HttpSession _tail;
Timer _timer;
_HttpSessionManager() : _sessions = {};
String createSessionId() {
const int _KEY_LENGTH = 16; // 128 bits.
var data = _CryptoUtils.getRandomBytes(_KEY_LENGTH);
return _CryptoUtils.bytesToHex(data);
}
_HttpSession getSession(String id) => _sessions[id];
_HttpSession createSession() {
var id = createSessionId();
// TODO(ajohnsen): Consider adding a limit and throwing an exception.
// Should be very unlikely however.
while (_sessions.containsKey(id)) {
id = createSessionId();
}
var session = _sessions[id] = new _HttpSession(this, id);
_addToTimeoutQueue(session);
return session;
}
void set sessionTimeout(int timeout) {
_sessionTimeout = timeout;
_stopTimer();
_startTimer();
}
void close() {
_stopTimer();
}
void _bumpToEnd(_HttpSession session) {
_removeFromTimeoutQueue(session);
_addToTimeoutQueue(session);
}
void _addToTimeoutQueue(_HttpSession session) {
if (_head == null) {
assert(_tail == null);
_tail = _head = session;
_startTimer();
} else {
assert(_timer != null);
assert(_tail != null);
// Add to end.
_tail._next = session;
session._prev = _tail;
_tail = session;
}
}
void _removeFromTimeoutQueue(_HttpSession session) {
if (session._next != null) {
session._next._prev = session._prev;
}
if (session._prev != null) {
session._prev._next = session._next;
}
if (_head == session) {
// We removed the head element, start new timer.
_head = session._next;
_stopTimer();
_startTimer();
}
if (_tail == session) {
_tail = session._prev;
}
session._next = session._prev = null;
}
void _timerTimeout() {
_stopTimer(); // Clear timer.
assert(_head != null);
var session = _head;
session.destroy(); // Will remove the session from timeout queue and map.
if (session._timeoutCallback != null) {
session._timeoutCallback();
}
}
void _startTimer() {
assert(_timer == null);
if (_head != null) {
int seconds = new DateTime.now().difference(_head.lastSeen).inSeconds;
_timer = new Timer(
new Duration(seconds: _sessionTimeout - seconds), _timerTimeout);
}
}
void _stopTimer() {
if (_timer != null) {
_timer.cancel();
_timer = null;
}
}
}

View file

@ -0,0 +1,18 @@
# Copyright (c) 2017, 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.
http_sdk_sources = [
"http.dart",
# The above file needs to be first if additional parts are added to the lib.
"crypto.dart",
"http_date.dart",
"http_headers.dart",
"http_impl.dart",
"http_parser.dart",
"http_session.dart",
"overrides.dart",
"websocket.dart",
"websocket_impl.dart",
]

View file

@ -0,0 +1,118 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart._http;
final _httpOverridesToken = new Object();
const _asyncRunZoned = runZoned;
/// This class facilitates overriding [HttpClient] with a mock implementation.
/// It should be extended by another class in client code with overrides
/// that construct a mock implementation. The implementation in this base class
/// defaults to the actual [HttpClient] implementation. For example:
///
/// ```
/// class MyHttpClient implements HttpClient {
/// ...
/// // An implementation of the HttpClient interface
/// ...
/// }
///
/// main() {
/// HttpOverrides.runZoned(() {
/// ...
/// // Operations will use MyHttpClient instead of the real HttpClient
/// // implementation whenever HttpClient is used.
/// ...
/// }, createHttpClient: (SecurityContext c) => new MyHttpClient(c));
/// }
/// ```
abstract class HttpOverrides {
static HttpOverrides _global;
static HttpOverrides get current {
return Zone.current[_httpOverridesToken] ?? _global;
}
/// The [HttpOverrides] to use in the root [Zone].
///
/// These are the [HttpOverrides] that will be used in the root Zone, and in
/// Zone's that do not set [HttpOverrides] and whose ancestors up to the root
/// Zone do not set [HttpOverrides].
static set global(HttpOverrides overrides) {
_global = overrides;
}
/// Runs [body] in a fresh [Zone] using the provided overrides.
static R runZoned<R>(R body(),
{HttpClient Function(SecurityContext) createHttpClient,
String Function(Uri uri, Map<String, String> environment)
findProxyFromEnvironment,
ZoneSpecification zoneSpecification,
Function onError}) {
HttpOverrides overrides =
new _HttpOverridesScope(createHttpClient, findProxyFromEnvironment);
return _asyncRunZoned<R>(body,
zoneValues: {_httpOverridesToken: overrides},
zoneSpecification: zoneSpecification,
onError: onError);
}
/// Runs [body] in a fresh [Zone] using the overrides found in [overrides].
///
/// Note that [overrides] should be an instance of a class that extends
/// [HttpOverrides].
static R runWithHttpOverrides<R>(R body(), HttpOverrides overrides,
{ZoneSpecification zoneSpecification, Function onError}) {
return _asyncRunZoned<R>(body,
zoneValues: {_httpOverridesToken: overrides},
zoneSpecification: zoneSpecification,
onError: onError);
}
/// Returns a new [HttpClient] using the given [context].
///
/// When this override is installed, this function overrides the behavior of
/// `new HttpClient`.
HttpClient createHttpClient(SecurityContext context) {
return new _HttpClient(context);
}
/// Resolves the proxy server to be used for HTTP connections.
///
/// When this override is installed, this function overrides the behavior of
/// `HttpClient.findProxyFromEnvironment`.
String findProxyFromEnvironment(Uri url, Map<String, String> environment) {
return _HttpClient._findProxyFromEnvironment(url, environment);
}
}
class _HttpOverridesScope extends HttpOverrides {
final HttpOverrides _previous = HttpOverrides.current;
final HttpClient Function(SecurityContext) _createHttpClient;
final String Function(Uri uri, Map<String, String> environment)
_findProxyFromEnvironment;
_HttpOverridesScope(this._createHttpClient, this._findProxyFromEnvironment);
@override
HttpClient createHttpClient(SecurityContext context) {
if (_createHttpClient != null) return _createHttpClient(context);
if (_previous != null) return _previous.createHttpClient(context);
return super.createHttpClient(context);
}
@override
String findProxyFromEnvironment(Uri url, Map<String, String> environment) {
if (_findProxyFromEnvironment != null) {
return _findProxyFromEnvironment(url, environment);
}
if (_previous != null) {
return _previous.findProxyFromEnvironment(url, environment);
}
return super.findProxyFromEnvironment(url, environment);
}
}

View file

@ -0,0 +1,497 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart._http;
/**
* WebSocket status codes used when closing a WebSocket connection.
*/
abstract class WebSocketStatus {
static const int normalClosure = 1000;
static const int goingAway = 1001;
static const int protocolError = 1002;
static const int unsupportedData = 1003;
static const int reserved1004 = 1004;
static const int noStatusReceived = 1005;
static const int abnormalClosure = 1006;
static const int invalidFramePayloadData = 1007;
static const int policyViolation = 1008;
static const int messageTooBig = 1009;
static const int missingMandatoryExtension = 1010;
static const int internalServerError = 1011;
static const int reserved1015 = 1015;
@Deprecated("Use normalClosure instead")
static const int NORMAL_CLOSURE = normalClosure;
@Deprecated("Use goingAway instead")
static const int GOING_AWAY = goingAway;
@Deprecated("Use protocolError instead")
static const int PROTOCOL_ERROR = protocolError;
@Deprecated("Use unsupportedData instead")
static const int UNSUPPORTED_DATA = unsupportedData;
@Deprecated("Use reserved1004 instead")
static const int RESERVED_1004 = reserved1004;
@Deprecated("Use noStatusReceived instead")
static const int NO_STATUS_RECEIVED = noStatusReceived;
@Deprecated("Use abnormalClosure instead")
static const int ABNORMAL_CLOSURE = abnormalClosure;
@Deprecated("Use invalidFramePayloadData instead")
static const int INVALID_FRAME_PAYLOAD_DATA = invalidFramePayloadData;
@Deprecated("Use policyViolation instead")
static const int POLICY_VIOLATION = policyViolation;
@Deprecated("Use messageTooBig instead")
static const int MESSAGE_TOO_BIG = messageTooBig;
@Deprecated("Use missingMandatoryExtension instead")
static const int MISSING_MANDATORY_EXTENSION = missingMandatoryExtension;
@Deprecated("Use internalServerError instead")
static const int INTERNAL_SERVER_ERROR = internalServerError;
@Deprecated("Use reserved1015 instead")
static const int RESERVED_1015 = reserved1015;
}
/// Options controlling compression in a [WebSocket].
///
/// A [CompressionOptions] instance can be passed to [WebSocket.connect], or
/// used in other similar places where [WebSocket] compression is configured.
///
/// In most cases the default [compressionDefault] is sufficient, but in some
/// situations, it might be desirable to use different compression parameters,
/// for example to preserve memory on small devices.
class CompressionOptions {
/// Default [WebSocket] compression configuration.
///
/// Enables compression with default window sizes and no reuse. This is the
/// default options used by [WebSocket.connect] if no [CompressionOptions] is
/// supplied.
///
/// * `clientNoContextTakeover`: false
/// * `serverNoContextTakeover`: false
/// * `clientMaxWindowBits`: null (default maximal window size of 15 bits)
/// * `serverMaxWindowBits`: null (default maximal window size of 15 bits)
static const CompressionOptions compressionDefault =
const CompressionOptions();
@Deprecated("Use compressionDefault instead")
static const CompressionOptions DEFAULT = compressionDefault;
/// No-compression configuration.
///
/// Disables compression when used as compression configuration for a
/// [WebSocket].
static const CompressionOptions compressionOff =
const CompressionOptions(enabled: false);
@Deprecated("Use compressionOff instead")
static const CompressionOptions OFF = compressionOff;
/// Whether the client will reuse its compression instances.
final bool clientNoContextTakeover;
/// Whether the server will reuse its compression instances.
final bool serverNoContextTakeover;
/// The maximal window size bit count requested by the client.
///
/// The windows size for the compression is always a power of two, so the
/// number of bits precisely determines the window size.
///
/// If set to `null`, the client has no preference, and the compression can
/// use up to its default maximum window size of 15 bits depending on the
/// server's preference.
final int clientMaxWindowBits;
/// The maximal window size bit count requested by the server.
///
/// The windows size for the compression is always a power of two, so the
/// number of bits precisely determines the window size.
///
/// If set to `null`, the server has no preference, and the compression can
/// use up to its default maximum window size of 15 bits depending on the
/// client's preference.
final int serverMaxWindowBits;
/// Whether WebSocket compression is enabled.
///
/// If not enabled, the remaining fields have no effect, and the
/// [compressionOff] instance can, and should, be reused instead of creating a
/// new instance with compression disabled.
final bool enabled;
const CompressionOptions(
{this.clientNoContextTakeover = false,
this.serverNoContextTakeover = false,
this.clientMaxWindowBits,
this.serverMaxWindowBits,
this.enabled = true});
/// Parses list of requested server headers to return server compression
/// response headers.
///
/// Uses [serverMaxWindowBits] value if set, otherwise will attempt to use
/// value from headers. Defaults to [WebSocket.DEFAULT_WINDOW_BITS]. Returns a
/// [_CompressionMaxWindowBits] object which contains the response headers and
/// negotiated max window bits.
_CompressionMaxWindowBits _createServerResponseHeader(HeaderValue requested) {
var info = new _CompressionMaxWindowBits();
int mwb;
String part;
if (requested?.parameters != null) {
part = requested.parameters[_serverMaxWindowBits];
}
if (part != null) {
if (part.length >= 2 && part.startsWith('0')) {
throw new ArgumentError("Illegal 0 padding on value.");
} else {
mwb = serverMaxWindowBits == null
? int.parse(part,
onError: (source) => _WebSocketImpl.DEFAULT_WINDOW_BITS)
: serverMaxWindowBits;
info.headerValue = "; server_max_window_bits=${mwb}";
info.maxWindowBits = mwb;
}
} else {
info.headerValue = "";
info.maxWindowBits = _WebSocketImpl.DEFAULT_WINDOW_BITS;
}
return info;
}
/// Returns default values for client compression request headers.
String _createClientRequestHeader(HeaderValue requested, int size) {
var info = "";
// If responding to a valid request, specify size
if (requested != null) {
info = "; client_max_window_bits=$size";
} else {
// Client request. Specify default
if (clientMaxWindowBits == null) {
info = "; client_max_window_bits";
} else {
info = "; client_max_window_bits=$clientMaxWindowBits";
}
if (serverMaxWindowBits != null) {
info += "; server_max_window_bits=$serverMaxWindowBits";
}
}
return info;
}
/// Create a Compression Header.
///
/// If [requested] is null or contains client request headers, returns Client
/// compression request headers with default settings for
/// `client_max_window_bits` header value. If [requested] contains server
/// response headers this method returns a Server compression response header
/// negotiating the max window bits for both client and server as requested
/// `server_max_window_bits` value. This method returns a
/// [_CompressionMaxWindowBits] object with the response headers and
/// negotiated `maxWindowBits` value.
_CompressionMaxWindowBits _createHeader([HeaderValue requested]) {
var info = new _CompressionMaxWindowBits("", 0);
if (!enabled) {
return info;
}
info.headerValue = _WebSocketImpl.PER_MESSAGE_DEFLATE;
if (clientNoContextTakeover &&
(requested == null ||
(requested != null &&
requested.parameters.containsKey(_clientNoContextTakeover)))) {
info.headerValue += "; client_no_context_takeover";
}
if (serverNoContextTakeover &&
(requested == null ||
(requested != null &&
requested.parameters.containsKey(_serverNoContextTakeover)))) {
info.headerValue += "; server_no_context_takeover";
}
var headerList = _createServerResponseHeader(requested);
info.headerValue += headerList.headerValue;
info.maxWindowBits = headerList.maxWindowBits;
info.headerValue +=
_createClientRequestHeader(requested, info.maxWindowBits);
return info;
}
}
/**
* The [WebSocketTransformer] provides the ability to upgrade a
* [HttpRequest] to a [WebSocket] connection. It supports both
* upgrading a single [HttpRequest] and upgrading a stream of
* [HttpRequest]s.
*
* To upgrade a single [HttpRequest] use the static [upgrade] method.
*
* HttpServer server;
* server.listen((request) {
* if (...) {
* WebSocketTransformer.upgrade(request).then((websocket) {
* ...
* });
* } else {
* // Do normal HTTP request processing.
* }
* });
*
* To transform a stream of [HttpRequest] events as it implements a
* stream transformer that transforms a stream of HttpRequest into a
* stream of WebSockets by upgrading each HttpRequest from the HTTP or
* HTTPS server, to the WebSocket protocol.
*
* server.transform(new WebSocketTransformer()).listen((webSocket) => ...);
*
* This transformer strives to implement WebSockets as specified by RFC6455.
*/
abstract class WebSocketTransformer
implements StreamTransformer<HttpRequest, WebSocket> {
/**
* Create a new [WebSocketTransformer].
*
* If [protocolSelector] is provided, [protocolSelector] will be called to
* select what protocol to use, if any were provided by the client.
* [protocolSelector] is should return either a [String] or a [Future]
* completing with a [String]. The [String] must exist in the list of
* protocols.
*
* If [compression] is provided, the [WebSocket] created will be configured
* to negotiate with the specified [CompressionOptions]. If none is specified
* then the [WebSocket] will be created with the default [CompressionOptions].
*/
factory WebSocketTransformer(
{/*String|Future<String>*/ protocolSelector(List<String> protocols),
CompressionOptions compression: CompressionOptions.compressionDefault}) {
return new _WebSocketTransformerImpl(protocolSelector, compression);
}
/**
* Upgrades a [HttpRequest] to a [WebSocket] connection. If the
* request is not a valid WebSocket upgrade request an HTTP response
* with status code 500 will be returned. Otherwise the returned
* future will complete with the [WebSocket] when the upgrade process
* is complete.
*
* If [protocolSelector] is provided, [protocolSelector] will be called to
* select what protocol to use, if any were provided by the client.
* [protocolSelector] is should return either a [String] or a [Future]
* completing with a [String]. The [String] must exist in the list of
* protocols.
*
* If [compression] is provided, the [WebSocket] created will be configured
* to negotiate with the specified [CompressionOptions]. If none is specified
* then the [WebSocket] will be created with the default [CompressionOptions].
*/
static Future<WebSocket> upgrade(HttpRequest request,
{protocolSelector(List<String> protocols),
CompressionOptions compression: CompressionOptions.compressionDefault}) {
return _WebSocketTransformerImpl._upgrade(
request, protocolSelector, compression);
}
/**
* Checks whether the request is a valid WebSocket upgrade request.
*/
static bool isUpgradeRequest(HttpRequest request) {
return _WebSocketTransformerImpl._isUpgradeRequest(request);
}
}
/**
* A two-way HTTP communication object for client or server applications.
*
* The stream exposes the messages received. A text message will be of type
* `String` and a binary message will be of type `List<int>`.
*/
abstract class WebSocket
implements
Stream<dynamic /*String|List<int>*/ >,
StreamSink<dynamic /*String|List<int>*/ > {
/**
* Possible states of the connection.
*/
static const int connecting = 0;
static const int open = 1;
static const int closing = 2;
static const int closed = 3;
@Deprecated("Use connecting instead")
static const int CONNECTING = connecting;
@Deprecated("Use open instead")
static const int OPEN = open;
@Deprecated("Use closing instead")
static const int CLOSING = closing;
@Deprecated("Use closed instead")
static const int CLOSED = closed;
/**
* Set and get the interval for sending ping signals. If a ping message is not
* answered by a pong message from the peer, the `WebSocket` is assumed
* disconnected and the connection is closed with a
* [WebSocketStatus.GOING_AWAY] close code. When a ping signal is sent, the
* pong message must be received within [pingInterval].
*
* There are never two outstanding pings at any given time, and the next ping
* timer starts when the pong is received.
*
* Set the [pingInterval] to `null` to disable sending ping messages.
*
* The default value is `null`.
*/
Duration pingInterval;
/**
* Create a new WebSocket connection. The URL supplied in [url]
* must use the scheme `ws` or `wss`.
*
* The [protocols] argument is specifying the subprotocols the
* client is willing to speak.
*
* The [headers] argument is specifying additional HTTP headers for
* setting up the connection. This would typically be the `Origin`
* header and potentially cookies. The keys of the map are the header
* fields and the values are either String or List<String>.
*
* If [headers] is provided, there are a number of headers
* which are controlled by the WebSocket connection process. These
* headers are:
*
* - `connection`
* - `sec-websocket-key`
* - `sec-websocket-protocol`
* - `sec-websocket-version`
* - `upgrade`
*
* If any of these are passed in the `headers` map they will be ignored.
*
* If the `url` contains user information this will be passed as basic
* authentication when setting up the connection.
*/
static Future<WebSocket> connect(String url,
{Iterable<String> protocols,
Map<String, dynamic> headers,
CompressionOptions compression:
CompressionOptions.compressionDefault}) =>
_WebSocketImpl.connect(url, protocols, headers, compression: compression);
@Deprecated('This constructor will be removed in Dart 2.0. Use `implements`'
' instead of `extends` if implementing this abstract class.')
WebSocket();
/**
* Creates a WebSocket from an already-upgraded socket.
*
* The initial WebSocket handshake must have occurred prior to this call. A
* WebSocket client can automatically perform the handshake using
* [WebSocket.connect], while a server can do so using
* [WebSocketTransformer.upgrade]. To manually upgrade an [HttpRequest],
* [HttpResponse.detachSocket] may be called.
*
* [protocol] should be the protocol negotiated by this handshake, if any.
*
* [serverSide] must be passed explicitly. If it's `false`, the WebSocket will
* act as the client and mask the messages it sends. If it's `true`, it will
* act as the server and will not mask its messages.
*
* If [compression] is provided, the [WebSocket] created will be configured
* to negotiate with the specified [CompressionOptions]. If none is specified
* then the [WebSocket] will be created with the default [CompressionOptions].
*/
factory WebSocket.fromUpgradedSocket(Socket socket,
{String protocol,
bool serverSide,
CompressionOptions compression: CompressionOptions.compressionDefault}) {
if (serverSide == null) {
throw new ArgumentError("The serverSide argument must be passed "
"explicitly to WebSocket.fromUpgradedSocket.");
}
return new _WebSocketImpl._fromSocket(
socket, protocol, compression, serverSide);
}
/**
* Returns the current state of the connection.
*/
int get readyState;
/**
* The extensions property is initially the empty string. After the
* WebSocket connection is established this string reflects the
* extensions used by the server.
*/
String get extensions;
/**
* The protocol property is initially the empty string. After the
* WebSocket connection is established the value is the subprotocol
* selected by the server. If no subprotocol is negotiated the
* value will remain [:null:].
*/
String get protocol;
/**
* The close code set when the WebSocket connection is closed. If
* there is no close code available this property will be [:null:]
*/
int get closeCode;
/**
* The close reason set when the WebSocket connection is closed. If
* there is no close reason available this property will be [:null:]
*/
String get closeReason;
/**
* Closes the WebSocket connection. Set the optional [code] and [reason]
* arguments to send close information to the remote peer. If they are
* omitted, the peer will see [WebSocketStatus.NO_STATUS_RECEIVED] code
* with no reason.
*/
Future close([int code, String reason]);
/**
* Sends data on the WebSocket connection. The data in [data] must
* be either a `String`, or a `List<int>` holding bytes.
*/
void add(/*String|List<int>*/ data);
/**
* Sends data from a stream on WebSocket connection. Each data event from
* [stream] will be send as a single WebSocket frame. The data from [stream]
* must be either `String`s, or `List<int>`s holding bytes.
*/
Future addStream(Stream stream);
/**
* Sends a text message with the text represented by [bytes].
*
* The [bytes] should be valid UTF-8 encoded Unicode characters. If they are
* not, the receiving end will close the connection.
*/
void addUtf8Text(List<int> bytes);
/**
* Gets the user agent used for WebSocket connections.
*/
static String get userAgent => _WebSocketImpl.userAgent;
/**
* Sets the user agent to use for WebSocket connections.
*/
static set userAgent(String userAgent) {
_WebSocketImpl.userAgent = userAgent;
}
}
class WebSocketException implements IOException {
final String message;
const WebSocketException([this.message = ""]);
String toString() => "WebSocketException: $message";
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,595 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/**
* Support for interoperating with JavaScript.
*
* This library provides access to JavaScript objects from Dart, allowing
* Dart code to get and set properties, and call methods of JavaScript objects
* and invoke JavaScript functions. The library takes care of converting
* between Dart and JavaScript objects where possible, or providing proxies if
* conversion isn't possible.
*
* This library does not yet make Dart objects usable from JavaScript, their
* methods and proeprties are not accessible, though it does allow Dart
* functions to be passed into and called from JavaScript.
*
* [JsObject] is the core type and represents a proxy of a JavaScript object.
* JsObject gives access to the underlying JavaScript objects properties and
* methods. `JsObject`s can be acquired by calls to JavaScript, or they can be
* created from proxies to JavaScript constructors.
*
* The top-level getter [context] provides a [JsObject] that represents the
* global object in JavaScript, usually `window`.
*
* The following example shows an alert dialog via a JavaScript call to the
* global function `alert()`:
*
* import 'dart:js';
*
* main() => context.callMethod('alert', ['Hello from Dart!']);
*
* This example shows how to create a [JsObject] from a JavaScript constructor
* and access its properties:
*
* import 'dart:js';
*
* main() {
* var object = new JsObject(context['Object']);
* object['greeting'] = 'Hello';
* object['greet'] = (name) => "${object['greeting']} $name";
* var message = object.callMethod('greet', ['JavaScript']);
* context['console'].callMethod('log', [message]);
* }
*
* ## Proxying and automatic conversion
*
* When setting properties on a JsObject or passing arguments to a Javascript
* method or function, Dart objects are automatically converted or proxied to
* JavaScript objects. When accessing JavaScript properties, or when a Dart
* closure is invoked from JavaScript, the JavaScript objects are also
* converted to Dart.
*
* Functions and closures are proxied in such a way that they are callable. A
* Dart closure assigned to a JavaScript property is proxied by a function in
* JavaScript. A JavaScript function accessed from Dart is proxied by a
* [JsFunction], which has a [apply] method to invoke it.
*
* The following types are transferred directly and not proxied:
*
* * "Basic" types: `null`, `bool`, `num`, `String`, `DateTime`
* * `Blob`
* * `Event`
* * `HtmlCollection`
* * `ImageData`
* * `KeyRange`
* * `Node`
* * `NodeList`
* * `TypedData`, including its subclasses like `Int32List`, but _not_
* `ByteBuffer`
* * `Window`
*
* ## Converting collections with JsObject.jsify()
*
* To create a JavaScript collection from a Dart collection use the
* [JsObject.jsify] constructor, which converts Dart [Map]s and [Iterable]s
* into JavaScript Objects and Arrays.
*
* The following expression creates a new JavaScript object with the properties
* `a` and `b` defined:
*
* var jsMap = new JsObject.jsify({'a': 1, 'b': 2});
*
* This expression creates a JavaScript array:
*
* var jsArray = new JsObject.jsify([1, 2, 3]);
*/
library dart.js;
import 'dart:collection' show HashMap, ListMixin;
import 'dart:_js_helper' show Primitives;
import 'dart:_foreign_helper' show JS;
import 'dart:_runtime' as dart;
final JsObject context = _wrapToDart(dart.global_);
/**
* Proxies a JavaScript object to Dart.
*
* The properties of the JavaScript object are accessible via the `[]` and
* `[]=` operators. Methods are callable via [callMethod].
*/
class JsObject {
// The wrapped JS object.
final dynamic _jsObject;
// This should only be called from _wrapToDart
JsObject._fromJs(this._jsObject) {
assert(_jsObject != null);
}
/**
* Constructs a new JavaScript object from [constructor] and returns a proxy
* to it.
*/
factory JsObject(JsFunction constructor, [List arguments]) {
var ctor = constructor._jsObject;
if (arguments == null) {
return _wrapToDart(JS('', 'new #()', ctor));
}
var unwrapped = List.from(arguments.map(_convertToJS));
return _wrapToDart(JS('', 'new #(...#)', ctor, unwrapped));
}
/**
* Constructs a [JsObject] that proxies a native Dart object; _for expert use
* only_.
*
* Use this constructor only if you wish to get access to JavaScript
* properties attached to a browser host object, such as a Node or Blob, that
* is normally automatically converted into a native Dart object.
*
* An exception will be thrown if [object] either is `null` or has the type
* `bool`, `num`, or `String`.
*/
factory JsObject.fromBrowserObject(object) {
if (object is num || object is String || object is bool || object == null) {
throw ArgumentError("object cannot be a num, string, bool, or null");
}
return _wrapToDart(_convertToJS(object));
}
/**
* Recursively converts a JSON-like collection of Dart objects to a
* collection of JavaScript objects and returns a [JsObject] proxy to it.
*
* [object] must be a [Map] or [Iterable], the contents of which are also
* converted. Maps and Iterables are copied to a new JavaScript object.
* Primitives and other transferable values are directly converted to their
* JavaScript type, and all other objects are proxied.
*/
factory JsObject.jsify(object) {
if ((object is! Map) && (object is! Iterable)) {
throw ArgumentError("object must be a Map or Iterable");
}
return _wrapToDart(_convertDataTree(object));
}
static _convertDataTree(data) {
var _convertedObjects = HashMap.identity();
_convert(o) {
if (_convertedObjects.containsKey(o)) {
return _convertedObjects[o];
}
if (o is Map) {
final convertedMap = JS('', '{}');
_convertedObjects[o] = convertedMap;
for (var key in o.keys) {
JS('', '#[#] = #', convertedMap, key, _convert(o[key]));
}
return convertedMap;
} else if (o is Iterable) {
var convertedList = [];
_convertedObjects[o] = convertedList;
convertedList.addAll(o.map(_convert));
return convertedList;
} else {
return _convertToJS(o);
}
}
return _convert(data);
}
/**
* Returns the value associated with [property] from the proxied JavaScript
* object.
*
* The type of [property] must be either [String] or [num].
*/
dynamic operator [](Object property) {
if (property is! String && property is! num) {
throw ArgumentError("property is not a String or num");
}
return _convertToDart(JS('', '#[#]', _jsObject, property));
}
/**
* Sets the value associated with [property] on the proxied JavaScript
* object.
*
* The type of [property] must be either [String] or [num].
*/
void operator []=(Object property, value) {
if (property is! String && property is! num) {
throw ArgumentError("property is not a String or num");
}
JS('', '#[#] = #', _jsObject, property, _convertToJS(value));
}
int get hashCode => 0;
bool operator ==(other) =>
other is JsObject && JS<bool>('!', '# === #', _jsObject, other._jsObject);
/**
* Returns `true` if the JavaScript object contains the specified property
* either directly or though its prototype chain.
*
* This is the equivalent of the `in` operator in JavaScript.
*/
bool hasProperty(property) {
if (property is! String && property is! num) {
throw ArgumentError("property is not a String or num");
}
return JS<bool>('!', '# in #', property, _jsObject);
}
/**
* Removes [property] from the JavaScript object.
*
* This is the equivalent of the `delete` operator in JavaScript.
*/
void deleteProperty(property) {
if (property is! String && property is! num) {
throw ArgumentError("property is not a String or num");
}
JS<bool>('!', 'delete #[#]', _jsObject, property);
}
/**
* Returns `true` if the JavaScript object has [type] in its prototype chain.
*
* This is the equivalent of the `instanceof` operator in JavaScript.
*/
bool instanceof(JsFunction type) {
return JS<bool>('!', '# instanceof #', _jsObject, _convertToJS(type));
}
/**
* Returns the result of the JavaScript objects `toString` method.
*/
String toString() {
try {
return JS<String>('!', 'String(#)', _jsObject);
} catch (e) {
return super.toString();
}
}
/**
* Calls [method] on the JavaScript object with the arguments [args] and
* returns the result.
*
* The type of [method] must be either [String] or [num].
*/
dynamic callMethod(method, [List args]) {
if (method is! String && method is! num) {
throw ArgumentError("method is not a String or num");
}
if (args != null) args = List.from(args.map(_convertToJS));
var fn = JS('', '#[#]', _jsObject, method);
if (JS<bool>('!', 'typeof(#) !== "function"', fn)) {
throw NoSuchMethodError(_jsObject, Symbol(method), args, {});
}
return _convertToDart(JS('', '#.apply(#, #)', fn, _jsObject, args));
}
}
/**
* Proxies a JavaScript Function object.
*/
class JsFunction extends JsObject {
/**
* Returns a [JsFunction] that captures its 'this' binding and calls [f]
* with the value of this passed as the first argument.
*/
factory JsFunction.withThis(Function f) {
return JsFunction._fromJs(JS(
'',
'function(/*...arguments*/) {'
' let args = [#(this)];'
' for (let arg of arguments) {'
' args.push(#(arg));'
' }'
' return #(#(...args));'
'}',
_convertToDart,
_convertToDart,
_convertToJS,
f));
}
JsFunction._fromJs(jsObject) : super._fromJs(jsObject);
/**
* Invokes the JavaScript function with arguments [args]. If [thisArg] is
* supplied it is the value of `this` for the invocation.
*/
dynamic apply(List args, {thisArg}) => _convertToDart(JS(
'',
'#.apply(#, #)',
_jsObject,
_convertToJS(thisArg),
args == null ? null : List.from(args.map(_convertToJS))));
}
// TODO(jmesserly): this is totally unnecessary in dev_compiler.
/** A [List] that proxies a JavaScript array. */
class JsArray<E> extends JsObject with ListMixin<E> {
/**
* Creates a new JavaScript array.
*/
JsArray() : super._fromJs([]);
/**
* Creates a new JavaScript array and initializes it to the contents of
* [other].
*/
JsArray.from(Iterable<E> other)
: super._fromJs([]..addAll(other.map(_convertToJS)));
JsArray._fromJs(jsObject) : super._fromJs(jsObject);
_checkIndex(int index) {
if (index is int && (index < 0 || index >= length)) {
throw RangeError.range(index, 0, length);
}
}
_checkInsertIndex(int index) {
if (index is int && (index < 0 || index >= length + 1)) {
throw RangeError.range(index, 0, length);
}
}
static _checkRange(int start, int end, int length) {
if (start < 0 || start > length) {
throw RangeError.range(start, 0, length);
}
if (end < start || end > length) {
throw RangeError.range(end, start, length);
}
}
// Methods required by ListMixin
E operator [](Object index) {
// TODO(justinfagnani): fix the semantics for non-ints
// dartbug.com/14605
if (index is num && index == index.toInt()) {
_checkIndex(index);
}
return super[index] as E;
}
void operator []=(Object index, value) {
// TODO(justinfagnani): fix the semantics for non-ints
// dartbug.com/14605
if (index is num && index == index.toInt()) {
_checkIndex(index);
}
super[index] = value;
}
int get length {
// Check the length honours the List contract.
var len = JS('', '#.length', _jsObject);
// JavaScript arrays have lengths which are unsigned 32-bit integers.
if (JS<bool>(
'!', 'typeof # === "number" && (# >>> 0) === #', len, len, len)) {
return JS<int>('!', '#', len);
}
throw StateError('Bad JsArray length');
}
void set length(int length) {
super['length'] = length;
}
// Methods overridden for better performance
void add(E value) {
callMethod('push', [value]);
}
void addAll(Iterable<E> iterable) {
var list = (JS<bool>('!', '# instanceof Array', iterable))
? iterable
: List.from(iterable);
callMethod('push', list);
}
void insert(int index, E element) {
_checkInsertIndex(index);
callMethod('splice', [index, 0, element]);
}
E removeAt(int index) {
_checkIndex(index);
return callMethod('splice', [index, 1])[0] as E;
}
E removeLast() {
if (length == 0) throw RangeError(-1);
return callMethod('pop') as E;
}
void removeRange(int start, int end) {
_checkRange(start, end, length);
callMethod('splice', [start, end - start]);
}
void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
_checkRange(start, end, this.length);
int length = end - start;
if (length == 0) return;
if (skipCount < 0) throw ArgumentError(skipCount);
var args = <Object>[start, length]
..addAll(iterable.skip(skipCount).take(length));
callMethod('splice', args);
}
void sort([int compare(E a, E b)]) {
// Note: arr.sort(null) is a type error in FF
callMethod('sort', compare == null ? [] : [compare]);
}
}
// Cross frame objects should not be considered browser types.
// We include the instanceof Object test to filter out cross frame objects
// on FireFox. Surprisingly on FireFox the instanceof Window test succeeds for
// cross frame windows while the instanceof Object test fails.
bool _isBrowserType(o) => JS(
'bool',
'# instanceof Object && ('
'# instanceof Blob || '
'# instanceof Event || '
'(window.KeyRange && # instanceof KeyRange) || '
'(window.IDBKeyRange && # instanceof IDBKeyRange) || '
'# instanceof ImageData || '
'# instanceof Node || '
// Int8Array.__proto__ is TypedArray.
'(window.Int8Array && # instanceof Int8Array.__proto__) || '
'# instanceof Window)',
o,
o,
o,
o,
o,
o,
o,
o,
o);
class _DartObject {
final _dartObj;
_DartObject(this._dartObj);
}
dynamic _convertToJS(dynamic o) {
if (o == null || o is String || o is num || o is bool || _isBrowserType(o)) {
return o;
} else if (o is DateTime) {
return Primitives.lazyAsJsDate(o);
} else if (o is JsObject) {
return o._jsObject;
} else if (o is Function) {
return _putIfAbsent(_jsProxies, o, _wrapDartFunction);
} else {
// TODO(jmesserly): for now, we wrap other objects, to keep compatibility
// with the original dart:js behavior.
return _putIfAbsent(_jsProxies, o, (o) => _DartObject(o));
}
}
dynamic _wrapDartFunction(f) {
var wrapper = JS(
'',
'function(/*...arguments*/) {'
' let args = Array.prototype.map.call(arguments, #);'
' return #(#(...args));'
'}',
_convertToDart,
_convertToJS,
f);
JS('', '#.set(#, #)', _dartProxies, wrapper, f);
return wrapper;
}
// converts a Dart object to a reference to a native JS object
// which might be a DartObject JS->Dart proxy
Object _convertToDart(o) {
if (o == null || o is String || o is num || o is bool || _isBrowserType(o)) {
return o;
} else if (JS('!', '# instanceof Date', o)) {
num ms = JS('!', '#.getTime()', o);
return DateTime.fromMillisecondsSinceEpoch(ms);
} else if (o is _DartObject &&
!identical(dart.getReifiedType(o), dart.jsobject)) {
return o._dartObj;
} else {
return _wrapToDart(o);
}
}
Object _wrapToDart(o) => _putIfAbsent(_dartProxies, o, _wrapToDartHelper);
Object _wrapToDartHelper(o) {
if (JS<bool>('!', 'typeof # == "function"', o)) {
return JsFunction._fromJs(o);
}
if (JS<bool>('!', '# instanceof Array', o)) {
return JsArray._fromJs(o);
}
return JsObject._fromJs(o);
}
final _dartProxies = JS('', 'new WeakMap()');
final _jsProxies = JS('', 'new WeakMap()');
Object _putIfAbsent(weakMap, o, getValue(o)) {
var value = JS('', '#.get(#)', weakMap, o);
if (value == null) {
value = getValue(o);
JS('', '#.set(#, #)', weakMap, o, value);
}
return value;
}
Expando<Function> _interopExpando = Expando<Function>();
/// Returns a wrapper around function [f] that can be called from JavaScript
/// using the package:js Dart-JavaScript interop.
///
/// For performance reasons in Dart2Js, by default Dart functions cannot be
/// passed directly to JavaScript unless this method is called to create
/// a Function compatible with both Dart and JavaScript.
/// Calling this method repeatedly on a function will return the same function.
/// The [Function] returned by this method can be used from both Dart and
/// JavaScript. We may remove the need to call this method completely in the
/// future if Dart2Js is refactored so that its function calling conventions
/// are more compatible with JavaScript.
F allowInterop<F extends Function>(F f) {
var ret = _interopExpando[f];
if (ret == null) {
ret = JS(
'',
'function (...args) {'
' return #(#, args);'
'}',
dart.dcall,
f);
_interopExpando[f] = ret;
}
return ret;
}
Expando<Function> _interopCaptureThisExpando = Expando<Function>();
/// Returns a [Function] that when called from JavaScript captures its 'this'
/// binding and calls [f] with the value of this passed as the first argument.
/// When called from Dart, [null] will be passed as the first argument.
///
/// See the documentation for [allowInterop]. This method should only be used
/// with package:js Dart-JavaScript interop.
Function allowInteropCaptureThis(Function f) {
var ret = _interopCaptureThisExpando[f];
if (ret == null) {
ret = JS(
'',
'function(...arguments) {'
' let args = [this];'
' args.push.apply(args, arguments);'
' return #(#, args);'
'}',
dart.dcall,
f);
_interopCaptureThisExpando[f] = ret;
}
return ret;
}

View file

@ -0,0 +1,126 @@
// Copyright (c) 2016, 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.
/// Utility methods to efficiently manipulate typed JSInterop objects in cases
/// where the name to call is not known at runtime. You should only use these
/// methods when the same effect cannot be achieved with @JS annotations.
/// These methods would be extension methods on JSObject if Dart supported
/// extension methods.
library dart.js_util;
import 'dart:_foreign_helper' show JS;
import 'dart:collection' show HashMap;
/// WARNING: performance of this method is much worse than other uitil
/// methods in this library. Only use this method as a last resort.
///
/// Recursively converts a JSON-like collection of Dart objects to a
/// collection of JavaScript objects and returns a [JsObject] proxy to it.
///
/// [object] must be a [Map] or [Iterable], the contents of which are also
/// converted. Maps and Iterables are copied to a new JavaScript object.
/// Primitives and other transferrable values are directly converted to their
/// JavaScript type, and all other objects are proxied.
jsify(object) {
if ((object is! Map) && (object is! Iterable)) {
throw ArgumentError("object must be a Map or Iterable");
}
return _convertDataTree(object);
}
_convertDataTree(data) {
var _convertedObjects = HashMap.identity();
_convert(o) {
if (_convertedObjects.containsKey(o)) {
return _convertedObjects[o];
}
if (o is Map) {
final convertedMap = JS('=Object', '{}');
_convertedObjects[o] = convertedMap;
for (var key in o.keys) {
JS('=Object', '#[#]=#', convertedMap, key, _convert(o[key]));
}
return convertedMap;
} else if (o is Iterable) {
var convertedList = [];
_convertedObjects[o] = convertedList;
convertedList.addAll(o.map(_convert));
return convertedList;
} else {
return o;
}
}
return _convert(data);
}
newObject() => JS('=Object', '{}');
hasProperty(o, name) => JS<bool>('!', '# in #', name, o);
getProperty(o, name) => JS('Object', '#[#]', o, name);
setProperty(o, name, value) => JS('', '#[#]=#', o, name, value);
callMethod(o, String method, List args) =>
JS('Object', '#[#].apply(#, #)', o, method, o, args);
instanceof(o, Function type) => JS<bool>('!', '# instanceof #', o, type);
callConstructor(Function constr, List arguments) {
if (arguments == null) {
return JS('Object', 'new #()', constr);
}
if (JS<bool>('!', '# instanceof Array', arguments)) {
int argumentCount = JS('!', '#.length', arguments);
switch (argumentCount) {
case 0:
return JS('Object', 'new #()', constr);
case 1:
var arg0 = JS('', '#[0]', arguments);
return JS('Object', 'new #(#)', constr, arg0);
case 2:
var arg0 = JS('', '#[0]', arguments);
var arg1 = JS('', '#[1]', arguments);
return JS('Object', 'new #(#, #)', constr, arg0, arg1);
case 3:
var arg0 = JS('', '#[0]', arguments);
var arg1 = JS('', '#[1]', arguments);
var arg2 = JS('', '#[2]', arguments);
return JS('Object', 'new #(#, #, #)', constr, arg0, arg1, arg2);
case 4:
var arg0 = JS('', '#[0]', arguments);
var arg1 = JS('', '#[1]', arguments);
var arg2 = JS('', '#[2]', arguments);
var arg3 = JS('', '#[3]', arguments);
return JS(
'Object', 'new #(#, #, #, #)', constr, arg0, arg1, arg2, arg3);
}
}
// The following code solves the problem of invoking a JavaScript
// constructor with an unknown number arguments.
// First bind the constructor to the argument list using bind.apply().
// The first argument to bind() is the binding of 't', so add 'null' to
// the arguments list passed to apply().
// After that, use the JavaScript 'new' operator which overrides any binding
// of 'this' with the new instance.
var args = <dynamic>[null]..addAll(arguments);
var factoryFunction = JS('', '#.bind.apply(#, #)', constr, constr, args);
// Without this line, calling factoryFunction as a constructor throws
JS<String>('!', 'String(#)', factoryFunction);
// This could return an UnknownJavaScriptObject, or a native
// object for which there is an interceptor
return JS('Object', 'new #()', factoryFunction);
// TODO(sra): Investigate:
//
// var jsObj = JS('', 'Object.create(#.prototype)', constr);
// JS('', '#.apply(#, #)', constr, jsObj,
// []..addAll(arguments.map(_convertToJS)));
// return _wrapToDart(jsObj);
}

View file

@ -0,0 +1,310 @@
// 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 libraries;
/**
* A bit flag used by [LibraryInfo] indicating that a library is used by dart2js
*/
const int DART2JS_PLATFORM = 1;
/**
* A bit flag used by [LibraryInfo] indicating that a library is used by the VM
*/
const int VM_PLATFORM = 2;
/// The contexts that a library can be used from.
enum Category {
/// Indicates that a library can be used in a browser context.
client,
/// Indicates that a library can be used in a command line context.
server,
/// Indicates that a library can be used from embedded devices.
embedded
}
Category parseCategory(String name) {
switch (name) {
case "Client":
return Category.client;
case "Server":
return Category.server;
case "Embedded":
return Category.embedded;
}
return null;
}
/// Mapping of "dart:" library name (e.g. "core") to information about that
/// library.
const Map<String, LibraryInfo> libraries = const {
"async": const LibraryInfo("async/async.dart",
categories: "Client,Server",
maturity: Maturity.STABLE,
dart2jsPatchPath: "_internal/js_runtime/lib/async_patch.dart"),
"collection": const LibraryInfo("collection/collection.dart",
categories: "Client,Server,Embedded",
maturity: Maturity.STABLE,
dart2jsPatchPath: "_internal/js_runtime/lib/collection_patch.dart"),
"convert": const LibraryInfo("convert/convert.dart",
categories: "Client,Server",
maturity: Maturity.STABLE,
dart2jsPatchPath: "_internal/js_runtime/lib/convert_patch.dart"),
"core": const LibraryInfo("core/core.dart",
categories: "Client,Server,Embedded",
maturity: Maturity.STABLE,
dart2jsPatchPath: "_internal/js_runtime/lib/core_patch.dart"),
"developer": const LibraryInfo("developer/developer.dart",
categories: "Client,Server,Embedded",
maturity: Maturity.UNSTABLE,
dart2jsPatchPath: "_internal/js_runtime/lib/developer_patch.dart"),
"html": const LibraryInfo("html/dart2js/html_dart2js.dart",
categories: "Client",
maturity: Maturity.WEB_STABLE,
platforms: DART2JS_PLATFORM),
"html_common": const LibraryInfo("html/html_common/html_common.dart",
categories: "Client",
maturity: Maturity.WEB_STABLE,
dart2jsPath: "html/html_common/html_common_dart2js.dart",
documented: false,
implementation: true),
"indexed_db": const LibraryInfo("indexed_db/dart2js/indexed_db_dart2js.dart",
categories: "Client",
maturity: Maturity.WEB_STABLE,
platforms: DART2JS_PLATFORM),
"_http":
const LibraryInfo("_http/http.dart", categories: "", documented: false),
"io": const LibraryInfo("io/io.dart",
categories: "Server",
dart2jsPatchPath: "_internal/js_runtime/lib/io_patch.dart"),
"isolate": const LibraryInfo("isolate/isolate.dart",
categories: "Client,Server",
maturity: Maturity.STABLE,
dart2jsPatchPath: "_internal/js_runtime/lib/isolate_patch.dart"),
"js": const LibraryInfo("js/dart2js/js_dart2js.dart",
categories: "Client",
maturity: Maturity.STABLE,
platforms: DART2JS_PLATFORM),
"js_util": const LibraryInfo("js_util/dart2js/js_util_dart2js.dart",
categories: "Client",
maturity: Maturity.STABLE,
platforms: DART2JS_PLATFORM),
"math": const LibraryInfo("math/math.dart",
categories: "Client,Server,Embedded",
maturity: Maturity.STABLE,
dart2jsPatchPath: "_internal/js_runtime/lib/math_patch.dart"),
"mirrors": const LibraryInfo("mirrors/mirrors.dart",
categories: "Client,Server",
maturity: Maturity.UNSTABLE,
dart2jsPatchPath: "_internal/js_runtime/lib/mirrors_patch.dart"),
"nativewrappers": const LibraryInfo("html/dartium/nativewrappers.dart",
categories: "Client",
implementation: true,
documented: false,
platforms: DART2JS_PLATFORM),
"typed_data": const LibraryInfo("typed_data/typed_data.dart",
categories: "Client,Server,Embedded",
maturity: Maturity.STABLE,
dart2jsPatchPath: "_internal/js_runtime/lib/typed_data_patch.dart"),
"_native_typed_data": const LibraryInfo(
"_internal/js_runtime/lib/native_typed_data.dart",
categories: "",
implementation: true,
documented: false,
platforms: DART2JS_PLATFORM),
"cli": const LibraryInfo("cli/cli.dart",
categories: "Server",
dart2jsPatchPath: "_internal/js_runtime/lib/cli_patch.dart"),
"svg": const LibraryInfo("svg/dart2js/svg_dart2js.dart",
categories: "Client",
maturity: Maturity.WEB_STABLE,
platforms: DART2JS_PLATFORM),
"web_audio": const LibraryInfo("web_audio/dart2js/web_audio_dart2js.dart",
categories: "Client",
maturity: Maturity.WEB_STABLE,
platforms: DART2JS_PLATFORM),
"web_gl": const LibraryInfo("web_gl/dart2js/web_gl_dart2js.dart",
categories: "Client",
maturity: Maturity.WEB_STABLE,
platforms: DART2JS_PLATFORM),
"web_sql": const LibraryInfo("web_sql/dart2js/web_sql_dart2js.dart",
categories: "Client",
maturity: Maturity.WEB_STABLE,
platforms: DART2JS_PLATFORM),
"_internal": const LibraryInfo("internal/internal.dart",
categories: "",
documented: false,
dart2jsPatchPath: "_internal/js_runtime/lib/internal_patch.dart"),
"_js_helper": const LibraryInfo("_internal/js_runtime/lib/js_helper.dart",
categories: "", documented: false, platforms: DART2JS_PLATFORM),
"_interceptors": const LibraryInfo(
"_internal/js_runtime/lib/interceptors.dart",
categories: "",
documented: false,
platforms: DART2JS_PLATFORM),
"_foreign_helper": const LibraryInfo(
"_internal/js_runtime/lib/foreign_helper.dart",
categories: "",
documented: false,
platforms: DART2JS_PLATFORM),
"_isolate_helper": const LibraryInfo(
"_internal/js_runtime/lib/isolate_helper.dart",
categories: "",
documented: false,
platforms: DART2JS_PLATFORM),
"_js_mirrors": const LibraryInfo("_internal/js_runtime/lib/js_mirrors.dart",
categories: "", documented: false, platforms: DART2JS_PLATFORM),
"_js_primitives": const LibraryInfo(
"_internal/js_runtime/lib/js_primitives.dart",
categories: "",
documented: false,
platforms: DART2JS_PLATFORM),
"_metadata": const LibraryInfo("html/html_common/metadata.dart",
categories: "", documented: false, platforms: DART2JS_PLATFORM),
"_debugger": const LibraryInfo("_internal/js_runtime/lib/debugger.dart",
category: "", documented: false, platforms: DART2JS_PLATFORM),
"_runtime": const LibraryInfo(
"_internal/js_runtime/lib/ddc_runtime/runtime.dart",
category: "",
documented: false,
platforms: DART2JS_PLATFORM),
};
/**
* Information about a "dart:" library.
*/
class LibraryInfo {
/**
* Path to the library's *.dart file relative to this file.
*/
final String path;
/**
* The categories in which the library can be used encoded as a
* comma-separated String.
*/
final String _categories;
/**
* Path to the dart2js library's *.dart file relative to this file
* or null if dart2js uses the common library path defined above.
* Access using the [#getDart2JsPath()] method.
*/
final String dart2jsPath;
/**
* Path to the dart2js library's patch file relative to this file
* or null if no dart2js patch file associated with this library.
* Access using the [#getDart2JsPatchPath()] method.
*/
final String dart2jsPatchPath;
/**
* True if this library is documented and should be shown to the user.
*/
final bool documented;
/**
* Bit flags indicating which platforms consume this library.
* See [DART2JS_LIBRARY] and [VM_LIBRARY].
*/
final int platforms;
/**
* True if the library contains implementation details for another library.
* The implication is that these libraries are less commonly used
* and that tools like Dart Editor should not show these libraries
* in a list of all libraries unless the user specifically asks the tool to
* do so.
*/
final bool implementation;
/**
* States the current maturity of this library.
*/
final Maturity maturity;
const LibraryInfo(this.path,
{String categories: "",
this.dart2jsPath,
this.dart2jsPatchPath,
this.implementation: false,
this.documented: true,
this.maturity: Maturity.UNSPECIFIED,
this.platforms: DART2JS_PLATFORM | VM_PLATFORM})
: _categories = categories;
bool get isDart2jsLibrary => (platforms & DART2JS_PLATFORM) != 0;
bool get isVmLibrary => (platforms & VM_PLATFORM) != 0;
/**
* The categories in which the library can be used.
*
* If no categories are specified, the library is internal and can not be
* loaded by user code.
*/
List<Category> get categories {
// `"".split(,)` returns [""] not [], so we handle that case separately.
if (_categories == "") return const <Category>[];
return _categories.split(",").map(parseCategory).toList();
}
bool get isInternal => categories.isEmpty;
/// The original "categories" String that was passed to the constructor.
///
/// Can be used to construct a slightly modified copy of this LibraryInfo.
String get categoriesString {
return _categories;
}
}
/**
* Abstraction to capture the maturity of a library.
*/
class Maturity {
final int level;
final String name;
final String description;
const Maturity(this.level, this.name, this.description);
String toString() => "$name: $level\n$description\n";
static const Maturity DEPRECATED = const Maturity(0, "Deprecated",
"This library will be remove before next major release.");
static const Maturity EXPERIMENTAL = const Maturity(
1,
"Experimental",
"This library is experimental and will likely change or be removed\n"
"in future versions.");
static const Maturity UNSTABLE = const Maturity(
2,
"Unstable",
"This library is in still changing and have not yet endured\n"
"sufficient real-world testing.\n"
"Backwards-compatibility is NOT guaranteed.");
static const Maturity WEB_STABLE = const Maturity(
3,
"Web Stable",
"This library is tracking the DOM evolution as defined by WC3.\n"
"Backwards-compatibility is NOT guaranteed.");
static const Maturity STABLE = const Maturity(
4,
"Stable",
"The library is stable. API backwards-compatibility is guaranteed.\n"
"However implementation details might change.");
static const Maturity LOCKED = const Maturity(5, "Locked",
"This library will not change except when serious bugs are encountered.");
static const Maturity UNSPECIFIED = const Maturity(-1, "Unspecified",
"The maturity for this library has not been specified.");
}

View file

@ -0,0 +1,472 @@
// 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 file for the dart:async library.
import 'dart:_js_helper' show notNull, patch, ReifyFunctionTypes;
import 'dart:_isolate_helper' show TimerImpl;
import 'dart:_foreign_helper' show JS, JSExportName;
import 'dart:_runtime' as dart;
/// This function adapts ES6 generators to implement Dart's async/await.
///
/// It's designed to interact with Dart's Future and follow Dart async/await
/// semantics.
///
/// See https://github.com/dart-lang/sdk/issues/27315 for ideas on reconciling
/// Dart's Future and ES6 Promise. At that point we should use native JS
/// async/await.
///
/// Inspired by `co`: https://github.com/tj/co/blob/master/index.js, which is a
/// stepping stone for ES async/await.
@JSExportName('async')
@ReifyFunctionTypes(false)
_async<T>(Function() initGenerator) {
var iter;
Object Function(Object) onValue;
Object Function(Object, StackTrace) onError;
onAwait(Object value) {
_Future f;
if (value is _Future) {
f = value;
} else if (value is Future) {
f = _Future();
_Future._chainForeignFuture(value, f);
} else {
f = _Future.value(value);
}
f = JS('', '#', f._thenAwait(onValue, onError));
return f;
}
onValue = (value) {
var iteratorResult = JS('', '#.next(#)', iter, value);
value = JS('', '#.value', iteratorResult);
return JS<bool>('!', '#.done', iteratorResult) ? value : onAwait(value);
};
// If the awaited Future throws, we want to convert this to an exception
// thrown from the `yield` point, as if it was thrown there.
//
// If the exception is not caught inside `gen`, it will emerge here, which
// will send it to anyone listening on this async function's Future<T>.
//
// In essence, we are giving the code inside the generator a chance to
// use try-catch-finally.
onError = (value, stackTrace) {
var iteratorResult = JS(
'', '#.throw(#)', iter, dart.createErrorWithStack(value, stackTrace));
value = JS('', '#.value', iteratorResult);
return JS<bool>('!', '#.done', iteratorResult) ? value : onAwait(value);
};
var zone = Zone.current;
if (!identical(zone, _rootZone)) {
onValue = zone.registerUnaryCallback(onValue);
onError = zone.registerBinaryCallback(onError);
}
var asyncFuture = _Future<T>();
// This will be set to true once we've yielded to the event loop.
//
// Before we've done that, we need to complete the future asynchronously to
// match dart2js/VM. See https://github.com/dart-lang/sdk/issues/33330
//
// Once we've yielded to the event loop we can complete synchronously.
// Other implementations call this `isSync` to indicate that.
bool isRunningAsEvent = false;
runBody() {
try {
iter = JS('', '#[Symbol.iterator]()', initGenerator());
var iteratorValue = JS('', '#.next(null)', iter);
var value = JS('', '#.value', iteratorValue);
if (JS<bool>('!', '#.done', iteratorValue)) {
// TODO(jmesserly): this is a workaround for ignored cast failures.
// Remove it once we've fixed those. We should be able to call:
//
// if (isRunningAsEvent) {
// asyncFuture._complete(value);
// } else {
// asyncFuture._asyncComplete(value);
// }
//
// But if the user code returns `Future<dynamic>` instead of
// `Future<T>`, that function won't recognize it as a future and will
// instead treat it as a completed value.
if (value is Future) {
if (value is _Future) {
_Future._chainCoreFuture(value, asyncFuture);
} else {
_Future._chainForeignFuture(value, asyncFuture);
}
} else if (isRunningAsEvent) {
asyncFuture._completeWithValue(JS('', '#', value));
} else {
asyncFuture._asyncComplete(JS('', '#', value));
}
} else {
_Future._chainCoreFuture(onAwait(value), asyncFuture);
}
} catch (e, s) {
if (isRunningAsEvent) {
_completeWithErrorCallback(asyncFuture, e, s);
} else {
_asyncCompleteWithErrorCallback(asyncFuture, e, s);
}
}
}
if (dart.startAsyncSynchronously) {
runBody();
isRunningAsEvent = true;
} else {
isRunningAsEvent = true;
scheduleMicrotask(runBody);
}
return asyncFuture;
}
@patch
class _AsyncRun {
@patch
static void _scheduleImmediate(void Function() callback) {
_scheduleImmediateClosure(callback);
}
// Lazily initialized.
static final _scheduleImmediateClosure = _initializeScheduleImmediate();
static void Function(void Function()) _initializeScheduleImmediate() {
// d8 support, see preambles/d8.js for the definiton of `scheduleImmediate`.
//
// TODO(jmesserly): do we need this? It's only for our d8 stack trace test.
if (JS('', '#.scheduleImmediate', dart.global_) != null) {
return _scheduleImmediateJSOverride;
}
return _scheduleImmediateWithPromise;
}
@ReifyFunctionTypes(false)
static void _scheduleImmediateJSOverride(void Function() callback) {
dart.addAsyncCallback();
JS('void', '#.scheduleImmediate(#)', dart.global_, () {
dart.removeAsyncCallback();
callback();
});
}
@ReifyFunctionTypes(false)
static Object _scheduleImmediateWithPromise(void Function() callback) {
dart.addAsyncCallback();
JS('', '#.Promise.resolve(null).then(#)', dart.global_, () {
dart.removeAsyncCallback();
callback();
});
}
}
@patch
class DeferredLibrary {
@patch
Future<Null> load() {
throw 'DeferredLibrary not supported. '
'please use the `import "lib.dart" deferred as lib` syntax.';
}
}
@patch
class Timer {
@patch
static Timer _createTimer(Duration duration, void callback()) {
int milliseconds = duration.inMilliseconds;
if (milliseconds < 0) milliseconds = 0;
return TimerImpl(milliseconds, callback);
}
@patch
static Timer _createPeriodicTimer(
Duration duration, void callback(Timer timer)) {
int milliseconds = duration.inMilliseconds;
if (milliseconds < 0) milliseconds = 0;
return TimerImpl.periodic(milliseconds, callback);
}
}
@patch
void _rethrow(Object error, StackTrace stackTrace) {
JS('', 'throw #', dart.createErrorWithStack(error, stackTrace));
}
/// Used by the compiler to implement `async*` functions.
///
/// This is inspired by _AsyncStarStreamController in dart-lang/sdk's
/// runtime/lib/core_patch.dart
///
/// Given input like:
///
/// foo() async* {
/// yield 1;
/// yield* bar();
/// print(await baz());
/// }
///
/// This compiles to:
///
/// function foo() {
/// return new (AsyncStarImplOfT()).new(function*(stream) {
/// if (stream.add(1)) return;
/// yield;
/// if (stream.addStream(bar()) return;
/// yield;
/// print(yield baz());
/// });
/// }
///
class _AsyncStarImpl<T> {
StreamController<T> controller;
Object Function(_AsyncStarImpl<T>) initGenerator;
@notNull
bool isSuspendedAtYieldStar = false;
@notNull
bool onListenReceived = false;
@notNull
bool isScheduled = false;
@notNull
bool isSuspendedAtYield = false;
/// Whether we're suspended at an `await`.
@notNull
bool isSuspendedAtAwait = false;
Completer cancellationCompleter;
Object jsIterator;
Null Function(Object, StackTrace) _handleErrorCallback;
void Function([Object]) _runBodyCallback;
_AsyncStarImpl(this.initGenerator) {
controller = StreamController(
onListen: JS('!', 'this.onListen.bind(this)'),
onResume: JS('!', 'this.onResume.bind(this)'),
onCancel: JS('!', 'this.onCancel.bind(this)'));
jsIterator = JS('!', '#[Symbol.iterator]()', initGenerator(this));
}
/// The stream produced by this `async*` function.
Stream<T> get stream => controller.stream;
/// Returns the callback used for error handling.
///
/// This callback throws the error back into the user code, at the appropriate
/// location (e.g. `await` `yield` or `yield*`). This gives user code a chance
/// to handle it try-catch. If they do not handle, the error gets routed to
/// the [stream] as an error via [addError].
///
/// As a performance optimization, this callback is only bound once to the
/// current [Zone]. This works because a single subscription stream should
/// always be running in its original zone. An `async*` method will always
/// save/restore the zone that was active when `listen()` was first called,
/// similar to a stream. This follows from section 16.14 of the Dart 4th
/// edition spec:
///
/// > If `f` is marked `async*` (9), then a fresh instance `s` implementing
/// > the built-in class `Stream` is associated with the invocation and
/// > immediately returned. When `s` is listened to, execution of the body of
/// > `f` will begin.
///
Null Function(Object, StackTrace) get handleError {
if (_handleErrorCallback == null) {
_handleErrorCallback = (error, StackTrace stackTrace) {
try {
JS('', '#.throw(#)', jsIterator,
dart.createErrorWithStack(error, stackTrace));
} catch (e, newStack) {
// The generator didn't catch the error, or it threw a new one.
// Make sure to propagate the new error.
addError(e, newStack);
}
};
var zone = Zone.current;
if (!identical(zone, Zone.root)) {
_handleErrorCallback = zone.bindBinaryCallback(_handleErrorCallback);
}
}
return _handleErrorCallback;
}
void scheduleGenerator() {
// TODO(jmesserly): is this isPaused check in the right place? Assuming the
// async* Stream yields, then is paused (by other code), the body will
// already be scheduled. This will cause at least one more iteration to
// run (adding another data item to the Stream) before actually pausing.
// It could be fixed by moving the `isPaused` check inside `runBody`.
if (isScheduled ||
controller.isPaused ||
isSuspendedAtYieldStar ||
isSuspendedAtAwait) {
return;
}
isScheduled = true;
// Capture the current zone. See comment on [handleError] for more
// information about this optimization.
var zone = Zone.current;
if (_runBodyCallback == null) {
_runBodyCallback = JS('!', '#.bind(this)', runBody);
if (!identical(zone, Zone.root)) {
var registered = zone.registerUnaryCallback(_runBodyCallback);
_runBodyCallback = ([arg]) => zone.runUnaryGuarded(registered, arg);
}
}
zone.scheduleMicrotask(_runBodyCallback);
}
void runBody(awaitValue) {
isScheduled = false;
isSuspendedAtYield = false;
isSuspendedAtAwait = false;
Object iterResult;
try {
iterResult = JS('', '#.next(#)', jsIterator, awaitValue);
} catch (e, s) {
addError(e, s);
return null;
}
if (JS('!', '#.done', iterResult)) {
close();
return null;
}
// If we're suspended at a yield/yield*, we're done for now.
if (isSuspendedAtYield || isSuspendedAtYieldStar) return null;
// Handle `await`: if we get a value passed to `yield` it means we are
// waiting on this Future. Make sure to prevent scheduling, and pass the
// value back as the result of the `yield`.
//
// TODO(jmesserly): is the timing here correct? The assumption here is
// that we should schedule `await` in `async*` the same as in `async`.
isSuspendedAtAwait = true;
FutureOr<Object> value = JS('', '#.value', iterResult);
// TODO(jmesserly): this logic was copied from `async` function impl.
_Future f;
if (value is _Future) {
f = value;
} else if (value is Future) {
f = _Future();
_Future._chainForeignFuture(value, f);
} else {
f = _Future.value(value);
}
f._thenAwait(_runBodyCallback, handleError);
}
/// Adds element to [stream] and returns true if the caller should terminate
/// execution of the generator.
///
/// This is called from generated code like this:
///
/// if (controller.add(1)) return;
/// yield;
//
// TODO(hausner): Per spec, the generator should be suspended before exiting
// when the stream is closed. We could add a getter like this:
//
// get isCancelled => controller.hasListener;
//
// The generator would translate a 'yield e' statement to
//
// controller.add(1);
// suspend; // this is `yield` in JS.
// if (controller.isCancelled) return;
bool add(T event) {
if (!onListenReceived) _fatal("yield before stream is listened to");
if (isSuspendedAtYield) _fatal("unexpected yield");
// If stream is cancelled, tell caller to exit the async generator.
if (!controller.hasListener) {
return true;
}
controller.add(event);
scheduleGenerator();
isSuspendedAtYield = true;
return false;
}
/// Adds the elements of [stream] into this [controller]'s stream, and returns
/// true if the caller should terminate execution of the generator.
///
/// The generator will be scheduled again when all of the elements of the
/// added stream have been consumed.
bool addStream(Stream<T> stream) {
if (!onListenReceived) _fatal("yield* before stream is listened to");
// If stream is cancelled, tell caller to exit the async generator.
if (!controller.hasListener) return true;
isSuspendedAtYieldStar = true;
var whenDoneAdding = controller.addStream(stream, cancelOnError: false);
whenDoneAdding.then((_) {
isSuspendedAtYieldStar = false;
scheduleGenerator();
if (!isScheduled) isSuspendedAtYield = true;
}, onError: handleError);
return false;
}
void addError(Object error, StackTrace stackTrace) {
if (cancellationCompleter != null && !cancellationCompleter.isCompleted) {
// If the stream has been cancelled, complete the cancellation future
// with the error.
cancellationCompleter.completeError(error, stackTrace);
} else if (controller.hasListener) {
controller.addError(error, stackTrace);
}
// No need to schedule the generator body here. This code is only
// called from the catch clause of the implicit try-catch-finally
// around the generator body. That is, we are on the error path out
// of the generator and do not need to run the generator again.
close();
}
void close() {
if (cancellationCompleter != null && !cancellationCompleter.isCompleted) {
// If the stream has been cancelled, complete the cancellation future
// with the error.
cancellationCompleter.complete();
}
controller.close();
}
onListen() {
assert(!onListenReceived);
onListenReceived = true;
scheduleGenerator();
}
onResume() {
if (isSuspendedAtYield) {
scheduleGenerator();
}
}
onCancel() {
if (controller.isClosed) {
return null;
}
if (cancellationCompleter == null) {
cancellationCompleter = Completer();
// Only resume the generator if it is suspended at a yield.
// Cancellation does not affect an async generator that is
// suspended at an await.
if (isSuspendedAtYield) {
scheduleGenerator();
}
}
return cancellationCompleter.future;
}
_fatal(String message) => throw StateError(message);
}

View file

@ -0,0 +1,10 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:_js_helper' show patch;
@patch
void _waitForEvent(int timeoutMillis) {
throw UnsupportedError("waitForEvent");
}

View file

@ -0,0 +1,602 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Patch file for dart:collection classes.
import 'dart:_foreign_helper' show JS, JSExportName;
import 'dart:_runtime' as dart;
import 'dart:_interceptors' show JSArray;
import 'dart:_js_helper'
show
NoInline,
NoSideEffects,
NoThrows,
patch,
LinkedMap,
IdentityMap,
CustomHashMap,
CustomKeyHashMap,
DartIterator,
notNull,
putLinkedMapKey;
@patch
class HashMap<K, V> {
@patch
factory HashMap(
{bool equals(K key1, K key2),
int hashCode(K key),
bool isValidKey(Object potentialKey)}) {
if (isValidKey == null) {
if (hashCode == null) {
if (equals == null) {
if (identical(K, String) || identical(K, int)) {
return IdentityMap<K, V>();
}
return LinkedMap<K, V>();
}
hashCode = dart.hashCode;
} else if (identical(identityHashCode, hashCode) &&
identical(identical, equals)) {
return IdentityMap<K, V>();
}
return CustomHashMap<K, V>(equals ?? dart.equals, hashCode);
}
return CustomKeyHashMap<K, V>(
equals ?? dart.equals, hashCode ?? dart.hashCode, isValidKey);
}
@patch
factory HashMap.identity() = IdentityMap<K, V>;
}
@patch
class LinkedHashMap<K, V> {
@patch
factory LinkedHashMap(
{bool equals(K key1, K key2),
int hashCode(K key),
bool isValidKey(Object potentialKey)}) {
if (isValidKey == null) {
if (hashCode == null) {
if (equals == null) {
if (identical(K, String) || identical(K, int)) {
return IdentityMap<K, V>();
}
return LinkedMap<K, V>();
}
hashCode = dart.hashCode;
} else if (identical(identityHashCode, hashCode) &&
identical(identical, equals)) {
return IdentityMap<K, V>();
}
return CustomHashMap<K, V>(equals ?? dart.equals, hashCode);
}
return CustomKeyHashMap<K, V>(
equals ?? dart.equals, hashCode ?? dart.hashCode, isValidKey);
}
@patch
factory LinkedHashMap.identity() = IdentityMap<K, V>;
}
@patch
class HashSet<E> {
@patch
factory HashSet(
{bool equals(E e1, E e2),
int hashCode(E e),
bool isValidKey(Object potentialKey)}) {
if (isValidKey == null) {
if (hashCode == null) {
if (equals == null) {
if (identical(E, String) || identical(E, int)) {
return _IdentityHashSet<E>();
}
return _HashSet<E>();
}
hashCode = dart.hashCode;
} else if (identical(identityHashCode, hashCode) &&
identical(identical, equals)) {
return _IdentityHashSet<E>();
}
return _CustomHashSet<E>(
equals ?? dart.equals, hashCode ?? dart.hashCode);
}
return _CustomKeyHashSet<E>(
equals ?? dart.equals, hashCode ?? dart.hashCode, isValidKey);
}
@patch
factory HashSet.identity() = _IdentityHashSet<E>;
}
@patch
class LinkedHashSet<E> {
@patch
factory LinkedHashSet(
{bool equals(E e1, E e2),
int hashCode(E e),
bool isValidKey(Object potentialKey)}) {
if (isValidKey == null) {
if (hashCode == null) {
if (equals == null) {
if (identical(E, String) || identical(E, int)) {
return _IdentityHashSet<E>();
}
return _HashSet<E>();
}
hashCode = dart.hashCode;
} else if (identical(identityHashCode, hashCode) &&
identical(identical, equals)) {
return _IdentityHashSet<E>();
}
return _CustomHashSet<E>(
equals ?? dart.equals, hashCode ?? dart.hashCode);
}
return _CustomKeyHashSet<E>(
equals ?? dart.equals, hashCode ?? dart.hashCode, isValidKey);
}
@patch
factory LinkedHashSet.identity() = _IdentityHashSet<E>;
}
class _HashSet<E> extends _InternalSet<E>
implements HashSet<E>, LinkedHashSet<E> {
/// The backing store for this set.
///
/// Keys that use identity equality are stored directly. For other types of
/// keys, we first look them up (by hashCode) in the [_keyMap] map, then
/// we lookup the key in this map.
@notNull
final _map = JS('', 'new Set()');
/// Items that use custom equality semantics.
///
/// This maps from the item's hashCode to the canonical key, which is then
/// used to lookup the item in [_map]. Keeping the data in our primary backing
/// map gives us the ordering semantics requred by [LinkedHashMap], while
/// also providing convenient access to keys/values.
@notNull
final _keyMap = JS('', 'new Map()');
// We track the number of modifications done to the key set of the
// hash map to be able to throw when the map is modified while being
// iterated over.
//
// Value cycles after 2^30 modifications so that modification counts are
// always unboxed (Smi) values. Modification detection will be missed if you
// make exactly some multiple of 2^30 modifications between advances of an
// iterator.
@notNull
int _modifications = 0;
_HashSet();
Set<E> _newSet() => _HashSet<E>();
Set<R> _newSimilarSet<R>() => _HashSet<R>();
bool contains(Object key) {
if (key == null) {
key = null;
} else if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
dart.identityEquals)) {
@notNull
var k = key;
var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, k.hashCode);
if (buckets != null) {
for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
k = JS('', '#[#]', buckets, i);
if (k == key) return true;
}
}
return false;
}
return JS<bool>('!', '#.has(#)', _map, key);
}
E lookup(Object key) {
if (key == null) return null;
if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
dart.identityEquals)) {
@notNull
var k = key;
var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, k.hashCode);
if (buckets != null) {
for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
k = JS('', '#[#]', buckets, i);
if (k == key) return JS('', '#', k);
}
}
return null;
}
return JS('', '#.has(#) ? # : null', _map, key, key);
}
bool add(E key) {
var map = _map;
if (key == null) {
if (JS('', '#.has(null)', map)) return false;
key = null;
} else if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
dart.identityEquals)) {
var keyMap = _keyMap;
@notNull
var k = key;
int hash = JS('!', '# & 0x3ffffff', k.hashCode);
var buckets = JS('', '#.get(#)', keyMap, hash);
if (buckets == null) {
JS('', '#.set(#, [#])', keyMap, hash, key);
} else {
for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
k = JS('', '#[#]', buckets, i);
if (k == key) return false;
}
JS('', '#.push(#)', buckets, key);
}
} else if (JS('', '#.has(#)', map, key)) {
return false;
}
JS('', '#.add(#)', map, key);
_modifications = (_modifications + 1) & 0x3ffffff;
return true;
}
void addAll(Iterable<E> objects) {
var map = _map;
int length = JS('', '#.size', map);
for (E key in objects) {
if (key == null) {
key = null; // converts undefined to null, if needed.
} else if (JS<bool>('!', '#[#] !== #', key,
dart.extensionSymbol('_equals'), dart.identityEquals)) {
key = putLinkedMapKey(key, _keyMap);
}
JS('', '#.add(#)', map, key);
}
if (length != JS<int>('!', '#.size', map)) {
_modifications = (_modifications + 1) & 0x3ffffff;
}
}
bool remove(Object key) {
if (key == null) {
key = null;
} else if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
dart.identityEquals)) {
@notNull
var k = key;
int hash = JS('!', '# & 0x3ffffff', k.hashCode);
var buckets = JS('', '#.get(#)', _keyMap, hash);
if (buckets == null) return false; // not found
for (int i = 0, n = JS('!', '#.length', buckets);;) {
k = JS('', '#[#]', buckets, i);
if (k == key) {
key = k;
if (n == 1) {
JS('', '#.delete(#)', _keyMap, hash);
} else {
JS('', '#.splice(#, 1)', buckets, i);
}
break;
}
if (++i >= n) return false; // not found
}
}
var map = _map;
if (JS<bool>('!', '#.delete(#)', map, key)) {
_modifications = (_modifications + 1) & 0x3ffffff;
return true;
}
return false;
}
void clear() {
var map = _map;
if (JS<int>('!', '#.size', map) > 0) {
JS('', '#.clear()', map);
JS('', '#.clear()', _keyMap);
_modifications = (_modifications + 1) & 0x3ffffff;
}
}
}
// Used for DDC const sets.
class _ImmutableSet<E> extends _HashSet<E> {
_ImmutableSet.from(JSArray entries) {
var map = _map;
for (Object key in entries) {
if (key == null) {
key = null; // converts undefined to null, if needed.
} else if (JS<bool>('!', '#[#] !== #', key,
dart.extensionSymbol('_equals'), dart.identityEquals)) {
key = putLinkedMapKey(key, _keyMap);
}
JS('', '#.add(#)', map, key);
}
}
bool add(Object other) => throw _unsupported();
void addAll(Object other) => throw _unsupported();
void clear() => throw _unsupported();
bool remove(Object key) => throw _unsupported();
static Error _unsupported() =>
UnsupportedError("Cannot modify unmodifiable set");
}
class _IdentityHashSet<E> extends _InternalSet<E>
implements HashSet<E>, LinkedHashSet<E> {
/// The backing store for this set.
@notNull
final _map = JS('', 'new Set()');
@notNull
int _modifications = 0;
_IdentityHashSet();
Set<E> _newSet() => _IdentityHashSet<E>();
Set<R> _newSimilarSet<R>() => _IdentityHashSet<R>();
bool contains(Object element) {
return JS('', '#.has(#)', _map, element);
}
E lookup(Object element) {
return JS('', '#.has(#)', _map, element) ? element : null;
}
bool add(E element) {
var map = _map;
if (JS<bool>('!', '#.has(#)', map, element)) return false;
JS('', '#.add(#)', map, element);
_modifications = (_modifications + 1) & 0x3ffffff;
return true;
}
void addAll(Iterable<E> objects) {
var map = _map;
int length = JS('', '#.size', map);
for (E key in objects) {
JS('', '#.add(#)', map, key);
}
if (length != JS<int>('!', '#.size', map)) {
_modifications = (_modifications + 1) & 0x3ffffff;
}
}
bool remove(Object element) {
if (JS<bool>('!', '#.delete(#)', _map, element)) {
_modifications = (_modifications + 1) & 0x3ffffff;
return true;
}
return false;
}
void clear() {
var map = _map;
if (JS<int>('!', '#.size', map) > 0) {
JS('', '#.clear()', map);
_modifications = (_modifications + 1) & 0x3ffffff;
}
}
}
class _CustomKeyHashSet<E> extends _CustomHashSet<E> {
_Predicate<Object> _validKey;
_CustomKeyHashSet(_Equality<E> equals, _Hasher<E> hashCode, this._validKey)
: super(equals, hashCode);
Set<E> _newSet() => _CustomKeyHashSet<E>(_equals, _hashCode, _validKey);
Set<R> _newSimilarSet<R>() => _HashSet<R>();
bool contains(Object element) {
// TODO(jmesserly): there is a subtle difference here compared to Dart 1.
// See the comment on CustomKeyHashMap.containsKey for more information.
// Treatment of `null` is different due to strong mode's requirement to
// perform an `element is E` check before calling equals/hashCode.
if (!_validKey(element)) return false;
return super.contains(element);
}
E lookup(Object element) {
if (!_validKey(element)) return null;
return super.lookup(element);
}
bool remove(Object element) {
if (!_validKey(element)) return false;
return super.remove(element);
}
}
class _CustomHashSet<E> extends _InternalSet<E>
implements HashSet<E>, LinkedHashSet<E> {
_Equality<E> _equals;
_Hasher<E> _hashCode;
// We track the number of modifications done to the key set of the
// hash map to be able to throw when the map is modified while being
// iterated over.
//
// Value cycles after 2^30 modifications so that modification counts are
// always unboxed (Smi) values. Modification detection will be missed if you
// make exactly some multiple of 2^30 modifications between advances of an
// iterator.
@notNull
int _modifications = 0;
/// The backing store for this set, used to handle ordering.
// TODO(jmesserly): a non-linked custom hash set could skip this.
@notNull
final _map = JS('', 'new Set()');
/// Our map used to map keys onto the canonical key that is stored in [_map].
@notNull
final _keyMap = JS('', 'new Map()');
_CustomHashSet(this._equals, this._hashCode);
Set<E> _newSet() => _CustomHashSet<E>(_equals, _hashCode);
Set<R> _newSimilarSet<R>() => _HashSet<R>();
bool contains(Object key) {
if (key is E) {
var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, _hashCode(key));
if (buckets != null) {
var equals = _equals;
for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
E k = JS('', '#[#]', buckets, i);
if (equals(k, key)) return true;
}
}
}
return false;
}
E lookup(Object key) {
if (key is E) {
var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, _hashCode(key));
if (buckets != null) {
var equals = _equals;
for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
E k = JS('', '#[#]', buckets, i);
if (equals(k, key)) return k;
}
}
}
return null;
}
bool add(E key) {
var keyMap = _keyMap;
var hash = JS<int>('!', '# & 0x3ffffff', _hashCode(key));
var buckets = JS('', '#.get(#)', keyMap, hash);
if (buckets == null) {
JS('', '#.set(#, [#])', keyMap, hash, key);
} else {
var equals = _equals;
for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
E k = JS('', '#[#]', buckets, i);
if (equals(k, key)) return false;
}
JS('', '#.push(#)', buckets, key);
}
JS('', '#.add(#)', _map, key);
_modifications = (_modifications + 1) & 0x3ffffff;
return true;
}
void addAll(Iterable<E> objects) {
// TODO(jmesserly): it'd be nice to skip the covariance check here.
for (E element in objects) add(element);
}
bool remove(Object key) {
if (key is E) {
var hash = JS<int>('!', '# & 0x3ffffff', _hashCode(key));
var keyMap = _keyMap;
var buckets = JS('', '#.get(#)', keyMap, hash);
if (buckets == null) return false; // not found
var equals = _equals;
for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
E k = JS('', '#[#]', buckets, i);
if (equals(k, key)) {
if (n == 1) {
JS('', '#.delete(#)', keyMap, hash);
} else {
JS('', '#.splice(#, 1)', buckets, i);
}
JS('', '#.delete(#)', _map, k);
_modifications = (_modifications + 1) & 0x3ffffff;
return true;
}
}
}
return false;
}
void clear() {
var map = _map;
if (JS<int>('!', '#.size', map) > 0) {
JS('', '#.clear()', map);
JS('', '#.clear()', _keyMap);
_modifications = (_modifications + 1) & 0x3ffffff;
}
}
}
/// Base class for our internal [LinkedHashSet]/[HashSet] implementations.
///
/// This implements the common functionality.
abstract class _InternalSet<E> extends _SetBase<E> {
@notNull
get _map;
@notNull
int get _modifications;
@notNull
int get length => JS<int>('!', '#.size', _map);
@notNull
bool get isEmpty => JS<bool>('!', '#.size == 0', _map);
@notNull
bool get isNotEmpty => JS<bool>('!', '#.size != 0', _map);
Iterator<E> get iterator => DartIterator<E>(_jsIterator());
@JSExportName('Symbol.iterator')
_jsIterator() {
var self = this;
var iterator = JS('', '#.values()', self._map);
int modifications = self._modifications;
return JS(
'',
'''{
next() {
if (# != #) {
throw #;
}
return #.next();
}
}''',
modifications,
self._modifications,
ConcurrentModificationError(self),
iterator);
}
}
@patch
abstract class _SplayTree<K, Node extends _SplayTreeNode<K>> {
@patch
Node _splayMin(Node node) {
Node current = node;
while (current.left != null) {
Node left = current.left;
current.left = left.right;
left.right = current;
current = left;
}
return current;
}
@patch
Node _splayMax(Node node) {
Node current = node;
while (current.right != null) {
Node right = current.right;
current.right = right.left;
right.left = current;
current = right;
}
return current;
}
}

View file

@ -0,0 +1,508 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Patch file for dart:convert library.
import 'dart:_js_helper' show argumentErrorValue, patch;
import 'dart:_foreign_helper' show JS;
import 'dart:_interceptors' show JSExtendableArray;
import 'dart:_internal' show MappedIterable, ListIterable;
import 'dart:collection' show Maps, LinkedHashMap, MapBase;
import 'dart:_native_typed_data' show NativeUint8List;
/**
* Parses [json] and builds the corresponding parsed JSON value.
*
* Parsed JSON values Nare of the types [num], [String], [bool], [Null],
* [List]s of parsed JSON values or [Map]s from [String] to parsed
* JSON values.
*
* The optional [reviver] function, if provided, is called once for each object
* or list property parsed. The arguments are the property name ([String]) or
* list index ([int]), and the value is the parsed value. The return value of
* the reviver will be used as the value of that property instead of the parsed
* value. The top level value is passed to the reviver with the empty string as
* a key.
*
* Throws [FormatException] if the input is not valid JSON text.
*/
@patch
_parseJson(String source, reviver(Object key, Object value)) {
if (source is! String) throw argumentErrorValue(source);
var parsed;
try {
parsed = JS('=Object|JSExtendableArray|Null|bool|num|String',
'JSON.parse(#)', source);
} catch (e) {
throw FormatException(JS<String>('!', 'String(#)', e));
}
if (reviver == null) {
return _convertJsonToDartLazy(parsed);
} else {
return _convertJsonToDart(parsed, reviver);
}
}
/**
* Walks the raw JavaScript value [json], replacing JavaScript Objects with
* Maps. [json] is expected to be freshly allocated so elements can be replaced
* in-place.
*/
_convertJsonToDart(json, reviver(Object key, Object value)) {
assert(reviver != null);
walk(e) {
// JavaScript null, string, number, bool are in the correct representation.
if (JS<bool>('!', '# == null', e) ||
JS<bool>('!', 'typeof # != "object"', e)) {
return e;
}
// This test is needed to avoid identifying '{"__proto__":[]}' as an Array.
// TODO(sra): Replace this test with cheaper '#.constructor === Array' when
// bug 621 below is fixed.
if (JS<bool>('!', 'Object.getPrototypeOf(#) === Array.prototype', e)) {
// In-place update of the elements since JS Array is a Dart List.
for (int i = 0; i < JS<int>('!', '#.length', e); i++) {
// Use JS indexing to avoid range checks. We know this is the only
// reference to the list, but the compiler will likely never be able to
// tell that this instance of the list cannot have its length changed by
// the reviver even though it later will be passed to the reviver at the
// outer level.
var item = JS('', '#[#]', e, i);
JS('', '#[#]=#', e, i, reviver(i, walk(item)));
}
return e;
}
// Otherwise it is a plain object, so copy to a JSON map, so we process
// and revive all entries recursively.
_JsonMap map = _JsonMap(e);
var processed = map._processed;
List<String> keys = map._computeKeys();
for (int i = 0; i < keys.length; i++) {
String key = keys[i];
var revived = reviver(key, walk(JS('', '#[#]', e, key)));
JS('', '#[#]=#', processed, key, revived);
}
// Update the JSON map structure so future access is cheaper.
map._original = processed; // Don't keep two objects around.
return map;
}
return reviver(null, walk(json));
}
_convertJsonToDartLazy(object) {
// JavaScript null and undefined are represented as null.
if (object == null) return null;
// JavaScript string, number, bool already has the correct representation.
if (JS<bool>('!', 'typeof # != "object"', object)) {
return object;
}
// This test is needed to avoid identifying '{"__proto__":[]}' as an array.
// TODO(sra): Replace this test with cheaper '#.constructor === Array' when
// bug https://code.google.com/p/v8/issues/detail?id=621 is fixed.
if (JS<bool>('!', 'Object.getPrototypeOf(#) !== Array.prototype', object)) {
return _JsonMap(object);
}
// Update the elements in place since JS arrays are Dart lists.
for (int i = 0; i < JS<int>('!', '#.length', object); i++) {
// Use JS indexing to avoid range checks. We know this is the only
// reference to the list, but the compiler will likely never be able to
// tell that this instance of the list cannot have its length changed by
// the reviver even though it later will be passed to the reviver at the
// outer level.
var item = JS('', '#[#]', object, i);
JS('', '#[#]=#', object, i, _convertJsonToDartLazy(item));
}
return object;
}
class _JsonMap extends MapBase<String, dynamic> {
// The original JavaScript object remains unchanged until
// the map is eventually upgraded, in which case we null it
// out to reclaim the memory used by it.
var _original;
// We keep track of the map entries that we have already
// processed by adding them to a separate JavaScript object.
var _processed = _newJavaScriptObject();
// If the data slot isn't null, it represents either the list
// of keys (for non-upgraded JSON maps) or the upgraded map.
var _data = null;
_JsonMap(this._original);
operator [](key) {
if (_isUpgraded) {
return _upgradedMap[key];
} else if (key is! String) {
return null;
} else {
var result = _getProperty(_processed, key);
if (_isUnprocessed(result)) result = _process(key);
return result;
}
}
int get length => _isUpgraded ? _upgradedMap.length : _computeKeys().length;
bool get isEmpty => length == 0;
bool get isNotEmpty => length > 0;
Iterable<String> get keys {
if (_isUpgraded) return _upgradedMap.keys;
return _JsonMapKeyIterable(this);
}
Iterable get values {
if (_isUpgraded) return _upgradedMap.values;
return MappedIterable(_computeKeys(), (each) => this[each]);
}
operator []=(key, value) {
if (_isUpgraded) {
_upgradedMap[key] = value;
} else if (containsKey(key)) {
var processed = _processed;
_setProperty(processed, key, value);
var original = _original;
if (!identical(original, processed)) {
_setProperty(original, key, null); // Reclaim memory.
}
} else {
_upgrade()[key] = value;
}
}
void addAll(Map<String, dynamic> other) {
other.forEach((key, value) {
this[key] = value;
});
}
bool containsValue(value) {
if (_isUpgraded) return _upgradedMap.containsValue(value);
List<String> keys = _computeKeys();
for (int i = 0; i < keys.length; i++) {
String key = keys[i];
if (this[key] == value) return true;
}
return false;
}
bool containsKey(key) {
if (_isUpgraded) return _upgradedMap.containsKey(key);
if (key is! String) return false;
return _hasProperty(_original, key);
}
putIfAbsent(key, ifAbsent()) {
if (containsKey(key)) return this[key];
var value = ifAbsent();
this[key] = value;
return value;
}
remove(Object key) {
if (!_isUpgraded && !containsKey(key)) return null;
return _upgrade().remove(key);
}
void clear() {
if (_isUpgraded) {
_upgradedMap.clear();
} else {
if (_data != null) {
// Clear the list of keys to make sure we force
// a concurrent modification error if anyone is
// currently iterating over it.
_data.clear();
}
_original = _processed = null;
_data = {};
}
}
void forEach(void f(String key, value)) {
if (_isUpgraded) return _upgradedMap.forEach(f);
List<String> keys = _computeKeys();
for (int i = 0; i < keys.length; i++) {
String key = keys[i];
// Compute the value under the assumption that the property
// is present but potentially not processed.
var value = _getProperty(_processed, key);
if (_isUnprocessed(value)) {
value = _convertJsonToDartLazy(_getProperty(_original, key));
_setProperty(_processed, key, value);
}
// Do the callback.
f(key, value);
// Check if invoking the callback function changed
// the key set. If so, throw an exception.
if (!identical(keys, _data)) {
throw ConcurrentModificationError(this);
}
}
}
// ------------------------------------------
// Private helper methods.
// ------------------------------------------
bool get _isUpgraded => _processed == null;
Map<String, dynamic> get _upgradedMap {
assert(_isUpgraded);
// 'cast' the union type to LinkedHashMap. It would be even better if we
// could 'cast' to the implementation type, since LinkedHashMap includes
// _JsonMap.
return JS('LinkedHashMap', '#', _data);
}
List<String> _computeKeys() {
assert(!_isUpgraded);
List keys = _data;
if (keys == null) {
keys = _data = _getPropertyNames(_original);
}
return JS('JSExtendableArray', '#', keys);
}
Map<String, dynamic> _upgrade() {
if (_isUpgraded) return _upgradedMap;
// Copy all the (key, value) pairs to a freshly allocated
// linked hash map thus preserving the ordering.
var result = <String, dynamic>{};
List<String> keys = _computeKeys();
for (int i = 0; i < keys.length; i++) {
String key = keys[i];
result[key] = this[key];
}
// We only upgrade when we need to extend the map, so we can
// safely force a concurrent modification error in case
// someone is iterating over the map here.
if (keys.isEmpty) {
keys.add(null);
} else {
keys.clear();
}
// Clear out the associated JavaScript objects and mark the
// map as having been upgraded.
_original = _processed = null;
_data = result;
assert(_isUpgraded);
return result;
}
_process(String key) {
if (!_hasProperty(_original, key)) return null;
var result = _convertJsonToDartLazy(_getProperty(_original, key));
return _setProperty(_processed, key, result);
}
// ------------------------------------------
// Private JavaScript helper methods.
// ------------------------------------------
static bool _hasProperty(object, String key) =>
JS<bool>('!', 'Object.prototype.hasOwnProperty.call(#,#)', object, key);
static _getProperty(object, String key) => JS('', '#[#]', object, key);
static _setProperty(object, String key, value) =>
JS('', '#[#]=#', object, key, value);
static List _getPropertyNames(object) =>
JS('JSExtendableArray', 'Object.keys(#)', object);
static bool _isUnprocessed(object) =>
JS<bool>('!', 'typeof(#)=="undefined"', object);
static _newJavaScriptObject() => JS('=Object', 'Object.create(null)');
}
class _JsonMapKeyIterable extends ListIterable<String> {
final _JsonMap _parent;
_JsonMapKeyIterable(this._parent);
int get length => _parent.length;
String elementAt(int index) {
return _parent._isUpgraded
? _parent.keys.elementAt(index)
: _parent._computeKeys()[index];
}
/// Although [ListIterable] defines its own iterator, we return the iterator
/// of the underlying list [_keys] in order to propagate
/// [ConcurrentModificationError]s.
Iterator<String> get iterator {
return _parent._isUpgraded
? _parent.keys.iterator
: _parent._computeKeys().iterator;
}
/// Delegate to [parent.containsKey] to ensure the performance expected
/// from [Map.keys.containsKey].
bool contains(Object key) => _parent.containsKey(key);
}
@patch
class JsonDecoder {
@patch
StringConversionSink startChunkedConversion(Sink<Object> sink) {
return _JsonDecoderSink(_reviver, sink);
}
}
/**
* Implements the chunked conversion from a JSON string to its corresponding
* object.
*
* The sink only creates one object, but its input can be chunked.
*/
// TODO(floitsch): don't accumulate everything before starting to decode.
class _JsonDecoderSink extends _StringSinkConversionSink {
final Function(Object key, Object value) _reviver;
final Sink<Object> _sink;
_JsonDecoderSink(this._reviver, this._sink) : super(StringBuffer(''));
void close() {
super.close();
StringBuffer buffer = _stringSink;
String accumulated = buffer.toString();
buffer.clear();
Object decoded = _parseJson(accumulated, _reviver);
_sink.add(decoded);
_sink.close();
}
}
@patch
class Utf8Decoder {
@patch
Converter<List<int>, T> fuse<T>(Converter<String, T> next) {
return super.fuse(next);
}
// Currently not intercepting UTF8 decoding.
@patch
static String _convertIntercepted(
bool allowMalformed, List<int> codeUnits, int start, int end) {
// Test `codeUnits is NativeUint8List`. Dart's NativeUint8List is
// implemented by JavaScript's Uint8Array.
if (JS<bool>('!', '# instanceof Uint8Array', codeUnits)) {
// JS 'cast' to avoid a downcast equivalent to the is-check we hand-coded.
NativeUint8List casted = JS<NativeUint8List>('!', '#', codeUnits);
return _convertInterceptedUint8List(allowMalformed, casted, start, end);
}
}
static String _convertInterceptedUint8List(
bool allowMalformed, NativeUint8List codeUnits, int start, int end) {
if (allowMalformed) {
// TextDecoder with option {fatal: false} does not produce the same result
// as [Utf8Decoder]. It disagrees on the number of `U+FFFD` (REPLACEMENT
// CHARACTER) generated for some malformed sequences. We could use
// TextDecoder with option {fatal: true}, catch the error, and re-try
// without acceleration. That turns out to be extremely slow (the Error
// captures a stack trace).
// TODO(31370): Bring Utf8Decoder into alignment with TextDecoder.
// TODO(sra): If we can't do that, can we detect valid input fast enough
// to use a check like the [_unsafe] check below?
return null;
}
var decoder = _decoder;
if (decoder == null) return null;
if (0 == start && end == null) {
return _useTextDecoderChecked(decoder, codeUnits);
}
int length = codeUnits.length;
end = RangeError.checkValidRange(start, end, length);
if (0 == start && end == codeUnits.length) {
return _useTextDecoderChecked(decoder, codeUnits);
}
return _useTextDecoderChecked(decoder,
JS<NativeUint8List>('!', '#.subarray(#, #)', codeUnits, start, end));
}
static String _useTextDecoderChecked(decoder, NativeUint8List codeUnits) {
if (_unsafe(codeUnits)) return null;
return _useTextDecoderUnchecked(decoder, codeUnits);
}
static String _useTextDecoderUnchecked(decoder, NativeUint8List codeUnits) {
// If the input is malformed, catch the exception and return `null` to fall
// back on unintercepted decoder. The fallback will either succeed in
// decoding, or report the problem better than TextDecoder.
try {
return JS<String>('!', '#.decode(#)', decoder, codeUnits);
} catch (e) {}
return null;
}
/// Returns `true` if [codeUnits] contains problematic encodings.
///
/// TextDecoder behaves differently to [Utf8Encoder] when the input encodes a
/// surrogate (U+D800 through U+DFFF). TextDecoder considers the surrogate to
/// be an encoding error and, depending on the `fatal` option, either throws
/// and Error or encodes the surrogate as U+FFFD. [Utf8Decoder] does not
/// consider the surrogate to be an error and returns the code unit encoded by
/// the surrogate.
///
/// Throwing an `Error` captures the stack, whoch makes it so expensive that
/// it is worth checking the input for surrogates and avoiding TextDecoder in
/// this case.
static bool _unsafe(NativeUint8List codeUnits) {
// Surrogates encode as (hex) ED Ax xx or ED Bx xx.
int limit = codeUnits.length - 2;
for (int i = 0; i < limit; i++) {
int unit1 = codeUnits[i];
if (unit1 == 0xED) {
int unit2 = JS('!', '#', codeUnits[i + 1]);
if ((unit2 & 0xE0) == 0xA0) return true;
}
}
return false;
}
//// TextDecoder is not defined on some browsers and on the stand-alone d8 and
/// jsshell engines. Use a lazy initializer to do feature detection once.
static final _decoder = () {
try {
// Use `{fatal: true}`. 'fatal' does not correspond exactly to
// `!allowMalformed`: TextDecoder rejects unpaired surrogates which
// [Utf8Decoder] accepts. In non-fatal mode, TextDecoder translates
// unpaired surrogates to REPLACEMENT CHARACTER (U+FFFD) whereas
// [Utf8Decoder] leaves the surrogate intact.
return JS('', 'new TextDecoder("utf-8", {fatal: true})');
} catch (e) {}
return null;
}();
}
@patch
int _scanOneByteCharacters(List<int> units, int from, int endIndex) {
final to = endIndex;
for (var i = from; i < to; i++) {
final unit = units[i];
if ((unit & _ONE_BYTE_LIMIT) != unit) return i - from;
}
return to - from;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,216 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Patch file for dart:developer library.
import 'dart:_js_helper' show patch, ForceInline, ReifyFunctionTypes;
import 'dart:_foreign_helper' show JS, JSExportName;
import 'dart:_runtime' as dart;
import 'dart:async';
import 'dart:convert' show json;
import 'dart:isolate';
@patch
@ForceInline()
bool debugger({bool when = true, String message}) {
if (when) {
JS('', 'debugger');
}
return when;
}
@patch
Object inspect(Object object) {
// Note: this log level does not show up by default in Chrome.
// This is used for communication with the debugger service.
JS('', 'console.debug("dart.developer.inspect", #)', object);
return object;
}
@patch
void log(String message,
{DateTime time,
int sequenceNumber,
int level = 0,
String name = '',
Zone zone,
Object error,
StackTrace stackTrace}) {
Object items =
JS('!', '{ message: #, name: #, level: # }', message, name, level);
if (time != null) JS('', '#.time = #', items, time);
if (sequenceNumber != null) {
JS('', '#.sequenceNumber = #', items, sequenceNumber);
}
if (zone != null) JS('', '#.zone = #', items, zone);
if (error != null) JS('', '#.error = #', items, error);
if (stackTrace != null) JS('', '#.stackTrace = #', items, stackTrace);
JS('', 'console.debug("dart.developer.log", #)', items);
}
final _extensions = Map<String, ServiceExtensionHandler>();
@patch
ServiceExtensionHandler _lookupExtension(String method) {
return _extensions[method];
}
@patch
_registerExtension(String method, ServiceExtensionHandler handler) {
_extensions[method] = handler;
JS('', 'console.debug("dart.developer.registerExtension", #)', method);
}
/// Returns a JS `Promise` that resolves with the result of invoking
/// [methodName] with an [encodedJson] map as its parameters.
///
/// This is used by the VM Service Prototcol to invoke extensions registered
/// with [registerExtension]. For example, in JS:
///
/// await sdk.developer.invokeExtension(
/// . "ext.flutter.inspector.getRootWidget", '{"objectGroup":""}');
///
@JSExportName('invokeExtension')
@ReifyFunctionTypes(false)
_invokeExtension(String methodName, String encodedJson) {
// TODO(vsm): We should factor this out as future<->promise.
return JS('', 'new #.Promise(#)', dart.global_,
(Function(Object) resolve, Function(Object) reject) async {
try {
var method = _lookupExtension(methodName);
var parameters = (json.decode(encodedJson) as Map).cast<String, String>();
var result = await method(methodName, parameters);
resolve(result._toString());
} catch (e) {
// TODO(vsm): Reject or encode in result?
reject('$e');
}
});
}
@patch
void _postEvent(String eventKind, String eventData) {
JS('', 'console.debug("dart.developer.postEvent", #, #)', eventKind,
eventData);
}
@patch
bool _isDartStreamEnabled() {
return false;
}
@patch
int _getTraceClock() {
// TODO.
return _clockValue++;
}
int _clockValue = 0;
@patch
int _getThreadCpuClock() {
return -1;
}
@patch
void _reportCompleteEvent(int start, int startCpu, String category, String name,
String argumentsAsJson) {
// TODO.
}
@patch
void _reportFlowEvent(int start, int startCpu, String category, String name,
int type, int id, String argumentsAsJson) {
// TODO.
}
@patch
void _reportInstantEvent(
int start, String category, String name, String argumentsAsJson) {
// TODO.
}
@patch
int _getNextAsyncId() {
return 0;
}
@patch
void _reportTaskEvent(int start, int taskId, String phase, String category,
String name, String argumentsAsJson) {
// TODO.
}
@patch
int _getServiceMajorVersion() {
return 0;
}
@patch
int _getServiceMinorVersion() {
return 0;
}
@patch
void _getServerInfo(SendPort sendPort) {
sendPort.send(null);
}
@patch
void _webServerControl(SendPort sendPort, bool enable) {
sendPort.send(null);
}
@patch
String _getIsolateIDFromSendPort(SendPort sendPort) {
return null;
}
@patch
class UserTag {
@patch
factory UserTag(String label) = _FakeUserTag;
@patch
static UserTag get defaultTag => _FakeUserTag._defaultTag;
}
class _FakeUserTag implements UserTag {
static Map _instances = {};
_FakeUserTag.real(this.label);
factory _FakeUserTag(String label) {
// Canonicalize by name.
var existingTag = _instances[label];
if (existingTag != null) {
return existingTag;
}
// Throw an exception if we've reached the maximum number of user tags.
if (_instances.length == UserTag.MAX_USER_TAGS) {
throw UnsupportedError(
'UserTag instance limit (${UserTag.MAX_USER_TAGS}) reached.');
}
// Create a new instance and add it to the instance map.
var instance = _FakeUserTag.real(label);
_instances[label] = instance;
return instance;
}
final String label;
UserTag makeCurrent() {
var old = _currentTag;
_currentTag = this;
return old;
}
static final UserTag _defaultTag = _FakeUserTag('Default');
}
var _currentTag = _FakeUserTag._defaultTag;
@patch
UserTag getCurrentTag() => _currentTag;

View file

@ -0,0 +1,54 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:core' hide Symbol;
import 'dart:core' as core show Symbol;
import 'dart:_js_primitives' show printString;
import 'dart:_js_helper' show patch;
import 'dart:_interceptors' show JSArray;
import 'dart:_foreign_helper' show JS;
import 'dart:_runtime' as dart;
@patch
class Symbol implements core.Symbol {
@patch
const Symbol(String name) : this._name = name;
@patch
int get hashCode {
int hash = JS('int|Null', '#._hashCode', this);
if (hash != null) return hash;
const arbitraryPrime = 664597;
hash = 0x1fffffff & (arbitraryPrime * _name.hashCode);
JS('', '#._hashCode = #', this, hash);
return hash;
}
@patch
toString() => 'Symbol("$_name")';
@patch
static String computeUnmangledName(Symbol symbol) => symbol._name;
}
@patch
void printToConsole(String line) {
printString('$line');
}
@patch
List<E> makeListFixedLength<E>(List<E> growableList) {
JSArray.markFixedList(growableList);
return growableList;
}
@patch
List<E> makeFixedListUnmodifiable<E>(List<E> fixedLengthList) {
JSArray.markUnmodifiableList(fixedLengthList);
return fixedLengthList;
}
@patch
Object extractTypeArguments<T>(T instance, Function extract) =>
dart.extractTypeArguments<T>(instance, extract);

View file

@ -0,0 +1,690 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:_js_helper' show patch;
import 'dart:async';
import 'dart:convert';
import 'dart:isolate' show SendPort;
import 'dart:typed_data';
@patch
class _Directory {
@patch
static _current(_Namespace namespace) {
throw UnsupportedError("Directory._current");
}
@patch
static _setCurrent(_Namespace namespace, Uint8List rawPath) {
throw UnsupportedError("Directory_SetCurrent");
}
@patch
static _createTemp(_Namespace namespace, Uint8List rawPath) {
throw UnsupportedError("Directory._createTemp");
}
@patch
static String _systemTemp(_Namespace namespace) {
throw UnsupportedError("Directory._systemTemp");
}
@patch
static _exists(_Namespace namespace, Uint8List rawPath) {
throw UnsupportedError("Directory._exists");
}
@patch
static _create(_Namespace namespace, Uint8List rawPath) {
throw UnsupportedError("Directory._create");
}
@patch
static _deleteNative(
_Namespace namespace, Uint8List rawPath, bool recursive) {
throw UnsupportedError("Directory._deleteNative");
}
@patch
static _rename(_Namespace namespace, Uint8List rawPath, String newPath) {
throw UnsupportedError("Directory._rename");
}
@patch
static void _fillWithDirectoryListing(
_Namespace namespace,
List<FileSystemEntity> list,
Uint8List rawPath,
bool recursive,
bool followLinks) {
throw UnsupportedError("Directory._fillWithDirectoryListing");
}
}
@patch
class _AsyncDirectoryListerOps {
@patch
factory _AsyncDirectoryListerOps(int pointer) {
throw UnsupportedError("Directory._list");
}
}
@patch
class _EventHandler {
@patch
static void _sendData(Object sender, SendPort sendPort, int data) {
throw UnsupportedError("EventHandler._sendData");
}
}
@patch
class FileStat {
@patch
static _statSync(_Namespace namespace, String path) {
throw UnsupportedError("FileStat.stat");
}
}
@patch
class FileSystemEntity {
@patch
static _getTypeNative(
_Namespace namespace, Uint8List rawPath, bool followLinks) {
throw UnsupportedError("FileSystemEntity._getType");
}
@patch
static _identicalNative(_Namespace namespace, String path1, String path2) {
throw UnsupportedError("FileSystemEntity._identical");
}
@patch
static _resolveSymbolicLinks(_Namespace namespace, Uint8List rawPath) {
throw UnsupportedError("FileSystemEntity._resolveSymbolicLinks");
}
}
@patch
class _File {
@patch
static _exists(_Namespace namespace, Uint8List rawPath) {
throw UnsupportedError("File._exists");
}
@patch
static _create(_Namespace namespace, Uint8List rawPath) {
throw UnsupportedError("File._create");
}
@patch
static _createLink(_Namespace namespace, Uint8List rawPath, String target) {
throw UnsupportedError("File._createLink");
}
@patch
static _linkTarget(_Namespace namespace, Uint8List rawPath) {
throw UnsupportedError("File._linkTarget");
}
@patch
static _deleteNative(_Namespace namespace, Uint8List rawPath) {
throw UnsupportedError("File._deleteNative");
}
@patch
static _deleteLinkNative(_Namespace namespace, Uint8List rawPath) {
throw UnsupportedError("File._deleteLinkNative");
}
@patch
static _rename(_Namespace namespace, Uint8List oldPath, String newPath) {
throw UnsupportedError("File._rename");
}
@patch
static _renameLink(_Namespace namespace, Uint8List oldPath, String newPath) {
throw UnsupportedError("File._renameLink");
}
@patch
static _copy(_Namespace namespace, Uint8List oldPath, String newPath) {
throw UnsupportedError("File._copy");
}
@patch
static _lengthFromPath(_Namespace namespace, Uint8List rawPath) {
throw UnsupportedError("File._lengthFromPath");
}
@patch
static _lastModified(_Namespace namespace, Uint8List rawPath) {
throw UnsupportedError("File._lastModified");
}
@patch
static _lastAccessed(_Namespace namespace, Uint8List rawPath) {
throw UnsupportedError("File._lastAccessed");
}
@patch
static _setLastModified(_Namespace namespace, Uint8List rawPath, int millis) {
throw UnsupportedError("File._setLastModified");
}
@patch
static _setLastAccessed(_Namespace namespace, Uint8List rawPath, int millis) {
throw UnsupportedError("File._setLastAccessed");
}
@patch
static _open(_Namespace namespace, Uint8List rawPath, int mode) {
throw UnsupportedError("File._open");
}
@patch
static int _openStdio(int fd) {
throw UnsupportedError("File._openStdio");
}
}
@patch
class _Namespace {
@patch
static void _setupNamespace(var namespace) {
throw UnsupportedError("_Namespace");
}
@patch
static _Namespace get _namespace {
throw UnsupportedError("_Namespace");
}
@patch
static int get _namespacePointer {
throw UnsupportedError("_Namespace");
}
}
@patch
class _RandomAccessFileOps {
@patch
factory _RandomAccessFileOps(int pointer) {
throw UnsupportedError("RandomAccessFile");
}
}
@patch
class _IOCrypto {
@patch
static Uint8List getRandomBytes(int count) {
throw UnsupportedError("_IOCrypto.getRandomBytes");
}
}
@patch
class _Platform {
@patch
static int _numberOfProcessors() {
throw UnsupportedError("Platform._numberOfProcessors");
}
@patch
static String _pathSeparator() {
throw UnsupportedError("Platform._pathSeparator");
}
@patch
static String _operatingSystem() {
throw UnsupportedError("Platform._operatingSystem");
}
@patch
static _operatingSystemVersion() {
throw UnsupportedError("Platform._operatingSystemVersion");
}
@patch
static _localHostname() {
throw UnsupportedError("Platform._localHostname");
}
@patch
static _executable() {
throw UnsupportedError("Platform._executable");
}
@patch
static _resolvedExecutable() {
throw UnsupportedError("Platform._resolvedExecutable");
}
@patch
static List<String> _executableArguments() {
throw UnsupportedError("Platform._executableArguments");
}
@patch
static String _packageRoot() {
throw UnsupportedError("Platform._packageRoot");
}
@patch
static String _packageConfig() {
throw UnsupportedError("Platform._packageConfig");
}
@patch
static _environment() {
throw UnsupportedError("Platform._environment");
}
@patch
static String _version() {
throw UnsupportedError("Platform._version");
}
@patch
static String _localeName() {
throw UnsupportedError("Platform._localeName");
}
@patch
static Uri _script() {
throw UnsupportedError("Platform._script");
}
}
@patch
class _ProcessUtils {
@patch
static void _exit(int status) {
throw UnsupportedError("ProcessUtils._exit");
}
@patch
static void _setExitCode(int status) {
throw UnsupportedError("ProcessUtils._setExitCode");
}
@patch
static int _getExitCode() {
throw UnsupportedError("ProcessUtils._getExitCode");
}
@patch
static void _sleep(int millis) {
throw UnsupportedError("ProcessUtils._sleep");
}
@patch
static int _pid(Process process) {
throw UnsupportedError("ProcessUtils._pid");
}
@patch
static Stream<ProcessSignal> _watchSignal(ProcessSignal signal) {
throw UnsupportedError("ProcessUtils._watchSignal");
}
}
@patch
class ProcessInfo {
@patch
static int get currentRss {
throw UnsupportedError("ProcessInfo.currentRss");
}
@patch
static int get maxRss {
throw UnsupportedError("ProcessInfo.maxRss");
}
}
@patch
class Process {
@patch
static Future<Process> start(String executable, List<String> arguments,
{String workingDirectory,
Map<String, String> environment,
bool includeParentEnvironment = true,
bool runInShell = false,
ProcessStartMode mode = ProcessStartMode.normal}) {
throw UnsupportedError("Process.start");
}
@patch
static Future<ProcessResult> run(String executable, List<String> arguments,
{String workingDirectory,
Map<String, String> environment,
bool includeParentEnvironment = true,
bool runInShell = false,
Encoding stdoutEncoding = systemEncoding,
Encoding stderrEncoding = systemEncoding}) {
throw UnsupportedError("Process.run");
}
@patch
static ProcessResult runSync(String executable, List<String> arguments,
{String workingDirectory,
Map<String, String> environment,
bool includeParentEnvironment = true,
bool runInShell = false,
Encoding stdoutEncoding = systemEncoding,
Encoding stderrEncoding = systemEncoding}) {
throw UnsupportedError("Process.runSync");
}
@patch
static bool killPid(int pid, [ProcessSignal signal = ProcessSignal.sigterm]) {
throw UnsupportedError("Process.killPid");
}
}
@patch
class InternetAddress {
@patch
static InternetAddress get LOOPBACK_IP_V4 {
throw UnsupportedError("InternetAddress.LOOPBACK_IP_V4");
}
@patch
static InternetAddress get LOOPBACK_IP_V6 {
throw UnsupportedError("InternetAddress.LOOPBACK_IP_V6");
}
@patch
static InternetAddress get ANY_IP_V4 {
throw UnsupportedError("InternetAddress.ANY_IP_V4");
}
@patch
static InternetAddress get ANY_IP_V6 {
throw UnsupportedError("InternetAddress.ANY_IP_V6");
}
@patch
factory InternetAddress(String address) {
throw UnsupportedError("InternetAddress");
}
@patch
static Future<List<InternetAddress>> lookup(String host,
{InternetAddressType type = InternetAddressType.any}) {
throw UnsupportedError("InternetAddress.lookup");
}
@patch
static InternetAddress _cloneWithNewHost(
InternetAddress address, String host) {
throw UnsupportedError("InternetAddress._cloneWithNewHost");
}
}
@patch
class NetworkInterface {
@patch
static bool get listSupported {
throw UnsupportedError("NetworkInterface.listSupported");
}
@patch
static Future<List<NetworkInterface>> list(
{bool includeLoopback = false,
bool includeLinkLocal = false,
InternetAddressType type = InternetAddressType.any}) {
throw UnsupportedError("NetworkInterface.list");
}
}
@patch
class RawServerSocket {
@patch
static Future<RawServerSocket> bind(address, int port,
{int backlog = 0, bool v6Only = false, bool shared = false}) {
throw UnsupportedError("RawServerSocket.bind");
}
}
@patch
class ServerSocket {
@patch
static Future<ServerSocket> bind(address, int port,
{int backlog = 0, bool v6Only = false, bool shared = false}) {
throw UnsupportedError("ServerSocket.bind");
}
}
@patch
class RawSocket {
@patch
static Future<RawSocket> connect(host, int port,
{sourceAddress, Duration timeout}) {
throw UnsupportedError("RawSocket constructor");
}
@patch
static Future<ConnectionTask<RawSocket>> startConnect(host, int port,
{sourceAddress}) {
throw UnsupportedError("RawSocket constructor");
}
}
@patch
class Socket {
@patch
static Future<Socket> _connect(host, int port,
{sourceAddress, Duration timeout}) {
throw UnsupportedError("Socket constructor");
}
@patch
static Future<ConnectionTask<Socket>> _startConnect(host, int port,
{sourceAddress}) {
throw UnsupportedError("Socket constructor");
}
}
@patch
class SecureSocket {
@patch
factory SecureSocket._(RawSecureSocket rawSocket) {
throw UnsupportedError("SecureSocket constructor");
}
}
@patch
class RawSynchronousSocket {
@patch
static RawSynchronousSocket connectSync(host, int port) {
throw UnsupportedError("RawSynchronousSocket.connectSync");
}
}
@patch
class RawSocketOption {
@patch
static int _getOptionValue(int key) {
throw UnsupportedError("RawSocketOption._getOptionValue");
}
}
@patch
class SecurityContext {
@patch
factory SecurityContext({bool withTrustedRoots = false}) {
throw UnsupportedError("SecurityContext constructor");
}
@patch
static SecurityContext get defaultContext {
throw UnsupportedError("default SecurityContext getter");
}
@patch
static bool get alpnSupported {
throw UnsupportedError("SecurityContext alpnSupported getter");
}
}
@patch
class X509Certificate {
@patch
factory X509Certificate._() {
throw UnsupportedError("X509Certificate constructor");
}
}
@patch
class RawDatagramSocket {
@patch
static Future<RawDatagramSocket> bind(host, int port,
{bool reuseAddress = true, bool reusePort = false, int ttl = 1}) {
throw UnsupportedError("RawDatagramSocket.bind");
}
}
@patch
class _SecureFilter {
@patch
factory _SecureFilter._() {
throw UnsupportedError("_SecureFilter._SecureFilter");
}
}
@patch
class _StdIOUtils {
@patch
static Stdin _getStdioInputStream(int fd) {
throw UnsupportedError("StdIOUtils._getStdioInputStream");
}
@patch
static _getStdioOutputStream(int fd) {
throw UnsupportedError("StdIOUtils._getStdioOutputStream");
}
@patch
static int _socketType(Socket socket) {
throw UnsupportedError("StdIOUtils._socketType");
}
@patch
static _getStdioHandleType(int fd) {
throw UnsupportedError("StdIOUtils._getStdioHandleType");
}
}
@patch
class _WindowsCodePageDecoder {
@patch
static String _decodeBytes(List<int> bytes) {
throw UnsupportedError("_WindowsCodePageDecoder._decodeBytes");
}
}
@patch
class _WindowsCodePageEncoder {
@patch
static List<int> _encodeString(String string) {
throw UnsupportedError("_WindowsCodePageEncoder._encodeString");
}
}
@patch
class RawZLibFilter {
@patch
static RawZLibFilter _makeZLibDeflateFilter(
bool gzip,
int level,
int windowBits,
int memLevel,
int strategy,
List<int> dictionary,
bool raw) {
throw UnsupportedError("_newZLibDeflateFilter");
}
@patch
static RawZLibFilter _makeZLibInflateFilter(
int windowBits, List<int> dictionary, bool raw) {
throw UnsupportedError("_newZLibInflateFilter");
}
}
@patch
class Stdin {
@patch
int readByteSync() {
throw UnsupportedError("Stdin.readByteSync");
}
@patch
bool get echoMode {
throw UnsupportedError("Stdin.echoMode");
}
@patch
void set echoMode(bool enabled) {
throw UnsupportedError("Stdin.echoMode");
}
@patch
bool get lineMode {
throw UnsupportedError("Stdin.lineMode");
}
@patch
void set lineMode(bool enabled) {
throw UnsupportedError("Stdin.lineMode");
}
@patch
bool get supportsAnsiEscapes {
throw UnsupportedError("Stdin.supportsAnsiEscapes");
}
}
@patch
class Stdout {
@patch
bool _hasTerminal(int fd) {
throw UnsupportedError("Stdout.hasTerminal");
}
@patch
int _terminalColumns(int fd) {
throw UnsupportedError("Stdout.terminalColumns");
}
@patch
int _terminalLines(int fd) {
throw UnsupportedError("Stdout.terminalLines");
}
@patch
static bool _supportsAnsiEscapes(int fd) {
throw UnsupportedError("Stdout.supportsAnsiEscapes");
}
}
@patch
class _FileSystemWatcher {
@patch
static Stream<FileSystemEvent> _watch(
String path, int events, bool recursive) {
throw UnsupportedError("_FileSystemWatcher.watch");
}
@patch
static bool get isSupported {
throw UnsupportedError("_FileSystemWatcher.isSupported");
}
}
@patch
class _IOService {
@patch
static Future _dispatch(int request, List data) {
throw UnsupportedError("_IOService._dispatch");
}
}

View file

@ -0,0 +1,125 @@
// 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 file for the dart:isolate library.
import 'dart:_js_helper' show patch, NoReifyGeneric;
import 'dart:async';
import "dart:typed_data" show TypedData;
@patch
class Isolate {
// `current` must be a getter, not just a final field,
// to match the external declaration.
@patch
static Isolate get current => _unsupported();
@patch
String get debugName => _unsupported();
@patch
static Future<Uri> get packageRoot => _unsupported();
@patch
static Future<Uri> get packageConfig => _unsupported();
@patch
static Future<Uri> resolvePackageUri(Uri packageUri) => _unsupported();
@patch
static Future<Isolate> spawn<T>(void entryPoint(T message), T message,
{bool paused = false,
bool errorsAreFatal,
SendPort onExit,
SendPort onError}) =>
_unsupported();
@patch
static Future<Isolate> spawnUri(Uri uri, List<String> args, var message,
{bool paused = false,
SendPort onExit,
SendPort onError,
bool errorsAreFatal,
bool checked,
Map<String, String> environment,
Uri packageRoot,
Uri packageConfig,
bool automaticPackageResolution = false}) =>
_unsupported();
@patch
void _pause(Capability resumeCapability) => _unsupported();
@patch
void resume(Capability resumeCapability) => _unsupported();
@patch
void addOnExitListener(SendPort responsePort, {Object response}) =>
_unsupported();
@patch
void removeOnExitListener(SendPort responsePort) => _unsupported();
@patch
void setErrorsFatal(bool errorsAreFatal) => _unsupported();
@patch
void kill({int priority = beforeNextEvent}) => _unsupported();
@patch
void ping(SendPort responsePort,
{Object response, int priority = immediate}) =>
_unsupported();
@patch
void addErrorListener(SendPort port) => _unsupported();
@patch
void removeErrorListener(SendPort port) => _unsupported();
}
/** Default factory for receive ports. */
@patch
class ReceivePort {
@patch
factory ReceivePort() = _ReceivePort;
@patch
factory ReceivePort.fromRawReceivePort(RawReceivePort rawPort) =>
_unsupported();
}
/// ReceivePort is supported by dev_compiler because async test packages
/// (async_helper, unittest) create a dummy receive port to keep the Dart VM
/// alive.
class _ReceivePort extends Stream implements ReceivePort {
close() {}
get sendPort => _unsupported();
listen(onData, {onError, onDone, cancelOnError}) => _unsupported();
}
@patch
class RawReceivePort {
@patch
factory RawReceivePort([void handler(event)]) => _unsupported();
}
@patch
class Capability {
@patch
factory Capability() => _unsupported();
}
@patch
abstract class TransferableTypedData {
@patch
factory TransferableTypedData.fromList(List<TypedData> list) =>
_unsupported();
}
@NoReifyGeneric()
T _unsupported<T>() {
throw UnsupportedError('dart:isolate is not supported on dart4web');
}

View file

@ -0,0 +1,348 @@
// 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 file for dart:math library.
import 'dart:_foreign_helper' show JS;
import 'dart:_js_helper' show patch, nullCheck, notNull;
import 'dart:typed_data' show ByteData;
@patch
@notNull
T min<T extends num>(@nullCheck T a, @nullCheck T b) =>
JS('-dynamic', r'Math.min(#, #)', a, b);
@patch
@notNull
T max<T extends num>(@nullCheck T a, @nullCheck T b) =>
JS('-dynamic', r'Math.max(#, #)', a, b);
@patch
@notNull
double sqrt(@nullCheck num x) => JS<num>('!', r'Math.sqrt(#)', x);
@patch
@notNull
double sin(@nullCheck num radians) => JS<num>('!', r'Math.sin(#)', radians);
@patch
@notNull
double cos(@nullCheck num radians) => JS<num>('!', r'Math.cos(#)', radians);
@patch
@notNull
double tan(@nullCheck num radians) => JS<num>('!', r'Math.tan(#)', radians);
@patch
@notNull
double acos(@nullCheck num x) => JS<num>('!', r'Math.acos(#)', x);
@patch
@notNull
double asin(@nullCheck num x) => JS<num>('!', r'Math.asin(#)', x);
@patch
@notNull
double atan(@nullCheck num x) => JS<num>('!', r'Math.atan(#)', x);
@patch
@notNull
double atan2(@nullCheck num a, @nullCheck num b) =>
JS<num>('!', r'Math.atan2(#, #)', a, b);
@patch
@notNull
double exp(@nullCheck num x) => JS<num>('!', r'Math.exp(#)', x);
@patch
@notNull
double log(@nullCheck num x) => JS<num>('!', r'Math.log(#)', x);
@patch
@notNull
num pow(@nullCheck num x, @nullCheck num exponent) =>
JS<num>('!', r'Math.pow(#, #)', x, exponent);
const int _POW2_32 = 0x100000000;
@patch
class Random {
static Random _secureRandom;
@patch
factory Random([int seed]) =>
(seed == null) ? const _JSRandom() : _Random(seed);
@patch
factory Random.secure() => _secureRandom ??= _JSSecureRandom();
}
class _JSRandom implements Random {
// The Dart2JS implementation of Random doesn't use a seed.
const _JSRandom();
@notNull
int nextInt(int max) {
if (max <= 0 || max > _POW2_32) {
throw RangeError("max must be in range 0 < max ≤ 2^32, was $max");
}
return JS("int", "(Math.random() * #) >>> 0", max);
}
/**
* Generates a positive random floating point value uniformly distributed on
* the range from 0.0, inclusive, to 1.0, exclusive.
*/
@notNull
double nextDouble() => JS("double", "Math.random()");
/**
* Generates a random boolean value.
*/
@notNull
bool nextBool() => JS("bool", "Math.random() < 0.5");
}
class _Random implements Random {
// Constants used by the algorithm or masking.
static const double _POW2_53_D = 1.0 * (0x20000000000000);
static const double _POW2_27_D = 1.0 * (1 << 27);
static const int _MASK32 = 0xFFFFFFFF;
// State comprised of two unsigned 32 bit integers.
@notNull
int _lo = 0;
@notNull
int _hi = 0;
// Implements:
// uint64_t hash = 0;
// do {
// hash = hash * 1037 ^ mix64((uint64_t)seed);
// seed >>= 64;
// } while (seed != 0 && seed != -1); // Limits for pos/neg seed.
// if (hash == 0) {
// hash = 0x5A17;
// }
// _lo = hash & _MASK_32;
// _hi = hash >> 32;
// and then does four _nextState calls to shuffle bits around.
_Random(int seed) {
int empty_seed = 0;
if (seed < 0) {
empty_seed = -1;
}
do {
int low = seed & _MASK32;
seed = (seed - low) ~/ _POW2_32;
int high = seed & _MASK32;
seed = (seed - high) ~/ _POW2_32;
// Thomas Wang's 64-bit mix function.
// http://www.concentric.net/~Ttwang/tech/inthash.htm
// via. http://web.archive.org/web/20071223173210/http://www.concentric.net/~Ttwang/tech/inthash.htm
// key = ~key + (key << 21);
int tmplow = low << 21;
int tmphigh = (high << 21) | (low >> 11);
tmplow = (~low & _MASK32) + tmplow;
low = tmplow & _MASK32;
high = (~high + tmphigh + ((tmplow - low) ~/ 0x100000000)) & _MASK32;
// key = key ^ (key >> 24).
tmphigh = high >> 24;
tmplow = (low >> 24) | (high << 8);
low ^= tmplow;
high ^= tmphigh;
// key = key * 265
tmplow = low * 265;
low = tmplow & _MASK32;
high = (high * 265 + (tmplow - low) ~/ 0x100000000) & _MASK32;
// key = key ^ (key >> 14);
tmphigh = high >> 14;
tmplow = (low >> 14) | (high << 18);
low ^= tmplow;
high ^= tmphigh;
// key = key * 21
tmplow = low * 21;
low = tmplow & _MASK32;
high = (high * 21 + (tmplow - low) ~/ 0x100000000) & _MASK32;
// key = key ^ (key >> 28).
tmphigh = high >> 28;
tmplow = (low >> 28) | (high << 4);
low ^= tmplow;
high ^= tmphigh;
// key = key + (key << 31);
tmplow = low << 31;
tmphigh = (high << 31) | (low >> 1);
tmplow += low;
low = tmplow & _MASK32;
high = (high + tmphigh + (tmplow - low) ~/ 0x100000000) & _MASK32;
// Mix end.
// seed = seed * 1037 ^ key;
tmplow = _lo * 1037;
_lo = tmplow & _MASK32;
_hi = (_hi * 1037 + (tmplow - _lo) ~/ 0x100000000) & _MASK32;
_lo ^= low;
_hi ^= high;
} while (seed != empty_seed);
if (_hi == 0 && _lo == 0) {
_lo = 0x5A17;
}
_nextState();
_nextState();
_nextState();
_nextState();
}
// 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 (0xFFFFDA61) is selected from "Numerical Recipes 3rd
// Edition" p.348 B1.
// Implements:
// var state = (A * _lo + _hi) & _MASK_64;
// _lo = state & _MASK_32;
// _hi = state >> 32;
void _nextState() {
// Simulate (0xFFFFDA61 * lo + hi) without overflowing 53 bits.
int tmpHi = 0xFFFF0000 * _lo; // At most 48 bits of significant result.
int tmpHiLo = tmpHi & _MASK32; // Get the lower 32 bits.
int tmpHiHi = tmpHi - tmpHiLo; // And just the upper 32 bits.
int tmpLo = 0xDA61 * _lo;
int tmpLoLo = tmpLo & _MASK32;
int tmpLoHi = tmpLo - tmpLoLo;
int newLo = tmpLoLo + tmpHiLo + _hi;
_lo = newLo & _MASK32;
int newLoHi = newLo - _lo;
_hi = ((tmpLoHi + tmpHiHi + newLoHi) ~/ _POW2_32) & _MASK32;
assert(_lo < _POW2_32);
assert(_hi < _POW2_32);
}
@notNull
int nextInt(@nullCheck int max) {
if (max <= 0 || max > _POW2_32) {
throw RangeError("max must be in range 0 < max ≤ 2^32, was $max");
}
if ((max & (max - 1)) == 0) {
// Fast case for powers of two.
_nextState();
return _lo & (max - 1);
}
int rnd32;
int result;
do {
_nextState();
rnd32 = _lo;
result = rnd32.remainder(max); // % max;
} while ((rnd32 - result + max) >= _POW2_32);
return result;
}
@notNull
double nextDouble() {
_nextState();
int bits26 = _lo & ((1 << 26) - 1);
_nextState();
int bits27 = _lo & ((1 << 27) - 1);
return (bits26 * _POW2_27_D + bits27) / _POW2_53_D;
}
@notNull
bool nextBool() {
_nextState();
return (_lo & 1) == 0;
}
}
class _JSSecureRandom implements Random {
// Reused buffer with room enough for a double.
final _buffer = ByteData(8);
_JSSecureRandom() {
var crypto = JS("", "self.crypto");
if (crypto != null) {
var getRandomValues = JS("", "#.getRandomValues", crypto);
if (getRandomValues != null) {
return;
}
}
throw UnsupportedError(
"No source of cryptographically secure random numbers available.");
}
/// Fill _buffer from [start] to `start + length` with random bytes.
void _getRandomBytes(int start, int length) {
JS("void", "crypto.getRandomValues(#)",
_buffer.buffer.asUint8List(start, length));
}
@notNull
bool nextBool() {
_getRandomBytes(0, 1);
return _buffer.getUint8(0).isOdd;
}
@notNull
double nextDouble() {
_getRandomBytes(1, 7);
// Set top bits 12 of double to 0x3FF which is the exponent for numbers
// between 1.0 and 2.0.
_buffer.setUint8(0, 0x3F);
int highByte = _buffer.getUint8(1);
_buffer.setUint8(1, highByte | 0xF0);
// Buffer now contains double in the range [1.0-2.0)
// with 52 bits of entropy (not 53).
// To get 53 bits, we extract the 53rd bit from higthByte before
// overwriting it, and add that as a least significant bit.
// The getFloat64 method is big-endian as default.
double result = _buffer.getFloat64(0) - 1.0;
if (highByte & 0x10 != 0) {
result += 1.1102230246251565e-16; // pow(2,-53).
}
return result;
}
@notNull
int nextInt(@nullCheck int max) {
if (max <= 0 || max > _POW2_32) {
throw RangeError("max must be in range 0 < max ≤ 2^32, was $max");
}
int byteCount = 1;
if (max > 0xFF) {
byteCount++;
if (max > 0xFFFF) {
byteCount++;
if (max > 0xFFFFFF) {
byteCount++;
}
}
}
_buffer.setUint32(0, 0);
int start = 4 - byteCount;
int randomLimit = pow(256, byteCount);
while (true) {
_getRandomBytes(start, byteCount);
// The getUint32 method is big-endian as default.
int random = _buffer.getUint32(0);
if (max & (max - 1) == 0) {
// Max is power of 2.
return random & (max - 1);
}
int result = random.remainder(max);
// Ensure results have equal probability by rejecting values in the
// last range of k*max .. 256**byteCount.
// TODO: Consider picking a higher byte count if the last range is a
// significant portion of the entire range - a 50% chance of having
// to use two more bytes is no worse than always using one more.
if (random - result + max < randomLimit) {
return result;
}
}
}
}

View file

@ -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.
// Patch library for dart:mirrors.
import 'dart:_js_helper' show patch;
import 'dart:_js_mirrors' as js;
import 'dart:_runtime' as dart;
@patch
class MirrorSystem {
@patch
LibraryMirror findLibrary(Symbol libraryName) {
return libraries.values
.singleWhere((library) => library.simpleName == libraryName);
}
@patch
static String getName(Symbol symbol) => js.getName(symbol);
@patch
static Symbol getSymbol(String name, [LibraryMirror library]) {
return js.getSymbol(name, library);
}
}
@patch
MirrorSystem currentMirrorSystem() => js.currentJsMirrorSystem;
@patch
InstanceMirror reflect(Object reflectee) => js.reflect(reflectee);
@patch
ClassMirror reflectClass(Type key) {
if (key is! Type || key == dynamic) {
throw ArgumentError('$key does not denote a class');
}
TypeMirror tm = reflectType(key);
if (tm is! ClassMirror) {
throw ArgumentError("$key does not denote a class");
}
return (tm as ClassMirror).originalDeclaration;
}
@patch
TypeMirror reflectType(Type type, [List<Type> typeArguments]) {
if (typeArguments != null) {
type = _instantiateClass(type, typeArguments);
}
return js.reflectType(type);
}
/// Instantiates the generic class [type] with [typeArguments] and returns the
/// result.
///
/// [type] may be instantiated with type arguments already. In that case, they
/// are ignored. For example calling this function with `(List<int>, [String])`
/// and `(List<dynamic>, [String])` will produce `List<String>` in both cases.
Type _instantiateClass(Type type, List<Type> typeArguments) {
var unwrapped = dart.unwrapType(type);
var genericClass = dart.getGenericClass(unwrapped);
if (genericClass == null) {
throw ArgumentError('Type `$type` must be generic to apply '
'type arguments: `$typeArguments`.');
}
var typeArgsLenth = typeArguments.length;
var unwrappedArgs = List(typeArgsLenth);
for (int i = 0; i < typeArgsLenth; i++) {
unwrappedArgs[i] = dart.unwrapType(typeArguments[i]);
}
var typeFormals = dart.getGenericTypeFormals(genericClass);
if (typeFormals.length != typeArgsLenth) {
throw ArgumentError('Type `$type` has ${typeFormals.length} type '
'parameters, but $typeArgsLenth type arguments were '
'passed: `$typeArguments`.');
}
// TODO(jmesserly): this does not validate bounds, as we don't have them
// available at runtime. Consider storing them when dart:mirrors is enabled.
return dart.wrapType(dart.instantiateClass(genericClass, unwrappedArgs));
}

View file

@ -0,0 +1,191 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:collection';
import 'dart:_js_helper' show patch;
import 'dart:_native_typed_data';
@patch
class ByteData {
@patch
factory ByteData(int length) = NativeByteData;
}
@patch
class Float32List {
@patch
factory Float32List(int length) = NativeFloat32List;
@patch
factory Float32List.fromList(List<double> elements) =
NativeFloat32List.fromList;
}
@patch
class Float64List {
@patch
factory Float64List(int length) = NativeFloat64List;
@patch
factory Float64List.fromList(List<double> elements) =
NativeFloat64List.fromList;
}
@patch
class Int16List {
@patch
factory Int16List(int length) = NativeInt16List;
@patch
factory Int16List.fromList(List<int> elements) = NativeInt16List.fromList;
}
@patch
class Int32List {
@patch
factory Int32List(int length) = NativeInt32List;
@patch
factory Int32List.fromList(List<int> elements) = NativeInt32List.fromList;
}
@patch
class Int8List {
@patch
factory Int8List(int length) = NativeInt8List;
@patch
factory Int8List.fromList(List<int> elements) = NativeInt8List.fromList;
}
@patch
class Uint32List {
@patch
factory Uint32List(int length) = NativeUint32List;
@patch
factory Uint32List.fromList(List<int> elements) = NativeUint32List.fromList;
}
@patch
class Uint16List {
@patch
factory Uint16List(int length) = NativeUint16List;
@patch
factory Uint16List.fromList(List<int> elements) = NativeUint16List.fromList;
}
@patch
class Uint8ClampedList {
@patch
factory Uint8ClampedList(int length) = NativeUint8ClampedList;
@patch
factory Uint8ClampedList.fromList(List<int> elements) =
NativeUint8ClampedList.fromList;
}
@patch
class Uint8List {
@patch
factory Uint8List(int length) = NativeUint8List;
@patch
factory Uint8List.fromList(List<int> elements) = NativeUint8List.fromList;
}
@patch
class Int64List {
@patch
factory Int64List(int length) {
throw UnsupportedError("Int64List not supported by dart2js.");
}
@patch
factory Int64List.fromList(List<int> elements) {
throw UnsupportedError("Int64List not supported by dart2js.");
}
}
@patch
class Uint64List {
@patch
factory Uint64List(int length) {
throw UnsupportedError("Uint64List not supported by dart2js.");
}
@patch
factory Uint64List.fromList(List<int> elements) {
throw UnsupportedError("Uint64List not supported by dart2js.");
}
}
@patch
class Int32x4List {
@patch
factory Int32x4List(int length) = NativeInt32x4List;
@patch
factory Int32x4List.fromList(List<Int32x4> elements) =
NativeInt32x4List.fromList;
}
@patch
class Float32x4List {
@patch
factory Float32x4List(int length) = NativeFloat32x4List;
@patch
factory Float32x4List.fromList(List<Float32x4> elements) =
NativeFloat32x4List.fromList;
}
@patch
class Float64x2List {
@patch
factory Float64x2List(int length) = NativeFloat64x2List;
@patch
factory Float64x2List.fromList(List<Float64x2> elements) =
NativeFloat64x2List.fromList;
}
@patch
class Float32x4 {
@patch
factory Float32x4(double x, double y, double z, double w) = NativeFloat32x4;
@patch
factory Float32x4.splat(double v) = NativeFloat32x4.splat;
@patch
factory Float32x4.zero() = NativeFloat32x4.zero;
@patch
factory Float32x4.fromInt32x4Bits(Int32x4 x) =
NativeFloat32x4.fromInt32x4Bits;
@patch
factory Float32x4.fromFloat64x2(Float64x2 v) = NativeFloat32x4.fromFloat64x2;
}
@patch
class Int32x4 {
@patch
factory Int32x4(int x, int y, int z, int w) = NativeInt32x4;
@patch
factory Int32x4.bool(bool x, bool y, bool z, bool w) = NativeInt32x4.bool;
@patch
factory Int32x4.fromFloat32x4Bits(Float32x4 x) =
NativeInt32x4.fromFloat32x4Bits;
}
@patch
class Float64x2 {
@patch
factory Float64x2(double x, double y) = NativeFloat64x2;
@patch
factory Float64x2.splat(double v) = NativeFloat64x2.splat;
@patch
factory Float64x2.zero() = NativeFloat64x2.zero;
@patch
factory Float64x2.fromFloat32x4(Float32x4 v) = NativeFloat64x2.fromFloat32x4;
}

View file

@ -0,0 +1,91 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart._js_helper;
/// Tells the optimizing compiler to always inline the annotated method.
class ForceInline {
const ForceInline();
}
class _NotNull {
const _NotNull();
}
/// Marks a variable or API to be non-nullable.
/// ****CAUTION******
/// This is currently unchecked, and hence should never be used
/// on any public interface where user code could subclass, implement,
/// or otherwise cause the contract to be violated.
/// TODO(leafp): Consider adding static checking and exposing
/// this to user code.
const notNull = _NotNull();
/// Marks a generic function or static method API to be not reified.
/// ****CAUTION******
/// This is currently unchecked, and hence should be used very carefully for
/// internal SDK APIs only.
class NoReifyGeneric {
const NoReifyGeneric();
}
/// Enables/disables reification of functions within the body of this function.
/// ****CAUTION******
/// This is currently unchecked, and hence should be used very carefully for
/// internal SDK APIs only.
class ReifyFunctionTypes {
final bool value;
const ReifyFunctionTypes(this.value);
}
class _NullCheck {
const _NullCheck();
}
/// Annotation indicating the parameter should default to the JavaScript
/// undefined constant.
const undefined = _Undefined();
class _Undefined {
const _Undefined();
}
/// Tells the development compiler to check a variable for null at its
/// declaration point, and then to assume that the variable is non-null
/// from that point forward.
/// ****CAUTION******
/// This is currently unchecked, and hence will not catch re-assignments
/// of a variable with null
const nullCheck = _NullCheck();
/// Tells the optimizing compiler that the annotated method cannot throw.
/// Requires @NoInline() to function correctly.
class NoThrows {
const NoThrows();
}
/// Tells the optimizing compiler to not inline the annotated method.
class NoInline {
const NoInline();
}
/// Marks a class as native and defines its JavaScript name(s).
class Native {
final String name;
const Native(this.name);
}
class JsPeerInterface {
/// The JavaScript type that we should match the API of.
/// Used for classes where Dart subclasses should be callable from JavaScript
/// matching the JavaScript calling conventions.
final String name;
const JsPeerInterface({this.name});
}
/// A Dart interface may only be implemented by a native JavaScript object
/// if it is marked with this annotation.
class SupportJsExtensionMethods {
const SupportJsExtensionMethods();
}

View file

@ -0,0 +1,197 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart._js_helper;
class CustomKeyHashMap<K, V> extends CustomHashMap<K, V> {
final _Predicate<Object> _validKey;
CustomKeyHashMap(_Equality<K> equals, _Hasher<K> hashCode, this._validKey)
: super(equals, hashCode);
@override
@notNull
bool containsKey(Object key) {
if (!_validKey(key)) return false;
return super.containsKey(key);
}
@override
V operator [](Object key) {
if (!_validKey(key)) return null;
return super[key];
}
@override
V remove(Object key) {
if (!_validKey(key)) return null;
return super.remove(key);
}
}
class CustomHashMap<K, V> extends InternalMap<K, V> {
/// The backing store for this map.
@notNull
final _map = JS('', 'new Map()');
/// Our map used to map keys onto the canonical key that is stored in [_map].
@notNull
final _keyMap = JS('', 'new Map()');
// We track the number of modifications done to the key set of the
// hash map to be able to throw when the map is modified while being
// iterated over.
//
// Value cycles after 2^30 modifications so that modification counts are
// always unboxed (Smi) values. Modification detection will be missed if you
// make exactly some multiple of 2^30 modifications between advances of an
// iterator.
@notNull
int _modifications = 0;
final _Equality<K> _equals;
final _Hasher<K> _hashCode;
CustomHashMap(this._equals, this._hashCode);
@notNull
int get length => JS<int>('!', '#.size', _map);
@notNull
bool get isEmpty => JS<bool>('!', '#.size == 0', _map);
@notNull
bool get isNotEmpty => JS<bool>('!', '#.size != 0', _map);
Iterable<K> get keys => _JSMapIterable<K>(this, true);
Iterable<V> get values => _JSMapIterable<V>(this, false);
@notNull
bool containsKey(Object key) {
if (key is K) {
var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, _hashCode(key));
if (buckets != null) {
var equals = _equals;
for (int i = 0, n = JS<int>('!', '#.length', buckets); i < n; i++) {
K k = JS('', '#[#]', buckets, i);
if (equals(k, key)) return true;
}
}
}
return false;
}
bool containsValue(Object value) {
for (var v in JS('', '#.values()', _map)) {
if (value == v) return true;
}
return false;
}
void addAll(Map<K, V> other) {
other.forEach((K key, V value) {
this[key] = value;
});
}
V operator [](Object key) {
if (key is K) {
var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, _hashCode(key));
if (buckets != null) {
var equals = _equals;
for (int i = 0, n = JS<int>('!', '#.length', buckets); i < n; i++) {
K k = JS('', '#[#]', buckets, i);
if (equals(k, key)) {
V value = JS('', '#.get(#)', _map, k);
return value == null ? null : value; // coerce undefined to null.
}
}
}
}
return null;
}
void operator []=(K key, V value) {
var keyMap = _keyMap;
int hash = JS('!', '# & 0x3ffffff', _hashCode(key));
var buckets = JS('', '#.get(#)', keyMap, hash);
if (buckets == null) {
JS('', '#.set(#, [#])', keyMap, hash, key);
} else {
var equals = _equals;
for (int i = 0, n = JS<int>('!', '#.length', buckets);;) {
K k = JS('', '#[#]', buckets, i);
if (equals(k, key)) {
key = k;
break;
}
if (++i >= n) {
JS('', '#.push(#)', buckets, key);
break;
}
}
}
JS('', '#.set(#, #)', _map, key, value);
_modifications = (_modifications + 1) & 0x3ffffff;
}
V putIfAbsent(K key, V ifAbsent()) {
var keyMap = _keyMap;
int hash = JS('!', '# & 0x3ffffff', _hashCode(key));
var buckets = JS('', '#.get(#)', keyMap, hash);
if (buckets == null) {
JS('', '#.set(#, [#])', keyMap, hash, key);
} else {
var equals = _equals;
for (int i = 0, n = JS<int>('!', '#.length', buckets); i < n; i++) {
K k = JS('', '#[#]', buckets, i);
if (equals(k, key)) return JS('', '#.get(#)', _map, k);
}
JS('', '#.push(#)', buckets, key);
}
V value = ifAbsent();
if (value == null) value = null; // coerce undefined to null.
JS('', '#.set(#, #)', _map, key, value);
_modifications = (_modifications + 1) & 0x3ffffff;
return value;
}
V remove(Object key) {
if (key is K) {
int hash = JS('!', '# & 0x3ffffff', _hashCode(key));
var keyMap = _keyMap;
var buckets = JS('', '#.get(#)', keyMap, hash);
if (buckets == null) return null; // not found
var equals = _equals;
for (int i = 0, n = JS<int>('!', '#.length', buckets); i < n; i++) {
K k = JS('', '#[#]', buckets, i);
if (equals(k, key)) {
if (n == 1) {
JS('', '#.delete(#)', keyMap, hash);
} else {
JS('', '#.splice(#, 1)', buckets, i);
}
var map = _map;
V value = JS('', '#.get(#)', map, k);
JS('', '#.delete(#)', map, k);
_modifications = (_modifications + 1) & 0x3ffffff;
return value == null ? null : value; // coerce undefined to null.
}
}
}
return null;
}
void clear() {
var map = _map;
if (JS<int>('!', '#.size', map) > 0) {
JS('', '#.clear()', map);
JS('', '#.clear()', _keyMap);
_modifications = (_modifications + 1) & 0x3ffffff;
}
}
}
typedef bool _Equality<K>(K a, K b);
typedef int _Hasher<K>(K object);
typedef bool _Predicate<T>(T value);

View file

@ -0,0 +1,537 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/// This library defines the operations that define and manipulate Dart
/// classes. Included in this are:
/// - Generics
/// - Class metadata
/// - Extension methods
///
// TODO(leafp): Consider splitting some of this out.
part of dart._runtime;
/// Returns a new type that mixes members from base and the mixin.
void applyMixin(to, from) {
JS('', '#[#] = #', to, _mixin, from);
var toProto = JS('', '#.prototype', to);
var fromProto = JS('', '#.prototype', from);
_copyMembers(toProto, fromProto);
_mixinSignature(to, from, _methodSig);
_mixinSignature(to, from, _fieldSig);
_mixinSignature(to, from, _getterSig);
_mixinSignature(to, from, _setterSig);
var mixinOnFn = JS('', '#[#]', from, mixinOn);
if (mixinOnFn != null) {
var proto = JS('', '#(#.__proto__).prototype', mixinOnFn, to);
_copyMembers(toProto, proto);
}
}
void _copyMembers(to, from) {
var names = getOwnNamesAndSymbols(from);
for (int i = 0, n = JS('!', '#.length', names); i < n; ++i) {
String name = JS('', '#[#]', names, i);
if (name == 'constructor') continue;
_copyMember(to, from, name);
}
return to;
}
void _copyMember(to, from, name) {
var desc = getOwnPropertyDescriptor(from, name);
if (JS('!', '# == Symbol.iterator', name)) {
// On native types, Symbol.iterator may already be present.
// TODO(jmesserly): investigate if we still need this.
// If so, we need to find a better solution.
// See https://github.com/dart-lang/sdk/issues/28324
var existing = getOwnPropertyDescriptor(to, name);
if (existing != null) {
if (JS('!', '#.writable', existing)) {
JS('', '#[#] = #.value', to, name, desc);
}
return;
}
}
var getter = JS('', '#.get', desc);
var setter = JS('', '#.set', desc);
if (getter != null) {
if (setter == null) {
var obj = JS(
'',
'#.set = { __proto__: #.__proto__, '
'set [#](x) { return super[#] = x; } }',
desc,
to,
name,
name);
JS('', '#.set = #.set', desc, getOwnPropertyDescriptor(obj, name));
}
} else if (setter != null) {
if (getter == null) {
var obj = JS(
'',
'#.get = { __proto__: #.__proto__, '
'get [#]() { return super[#]; } }',
desc,
to,
name,
name);
JS('', '#.get = #.get', desc, getOwnPropertyDescriptor(obj, name));
}
}
defineProperty(to, name, desc);
}
void _mixinSignature(to, from, kind) {
JS('', '#[#] = #', to, kind, () {
var baseMembers = _getMembers(JS('', '#.__proto__', to), kind);
var fromMembers = _getMembers(from, kind);
if (fromMembers == null) return baseMembers;
var toSignature = JS('', '{ __proto__: # }', baseMembers);
copyProperties(toSignature, fromMembers);
return toSignature;
});
}
final _mixin = JS('', 'Symbol("mixin")');
getMixin(clazz) => JS('', 'Object.hasOwnProperty.call(#, #) ? #[#] : null',
clazz, _mixin, clazz, _mixin);
final mixinOn = JS('', 'Symbol("mixinOn")');
@JSExportName('implements')
final implements_ = JS('', 'Symbol("implements")');
List Function() getImplements(clazz) => JS(
'',
'Object.hasOwnProperty.call(#, #) ? #[#] : null',
clazz,
implements_,
clazz,
implements_);
/// The Symbol for storing type arguments on a specialized generic type.
final _typeArguments = JS('', 'Symbol("typeArguments")');
final _originalDeclaration = JS('', 'Symbol("originalDeclaration")');
final mixinNew = JS('', 'Symbol("dart.mixinNew")');
/// Memoize a generic type constructor function.
generic(typeConstructor, setBaseClass) => JS('', '''(() => {
let length = $typeConstructor.length;
if (length < 1) {
$throwInternalError('must have at least one generic type argument');
}
let resultMap = new Map();
// TODO(vsm): Rethink how to clear the resultMap on hot restart.
// A simple clear via:
// _cacheMaps.push(resultMap);
// will break (a) we hoist type expressions in generated code and
// (b) we don't clear those type expressions in the presence of a
// hot restart. Not clearing this map (as we're doing now) should
// not affect correctness, but can result in a memory leak across
// multiple restarts.
function makeGenericType(...args) {
if (args.length != length && args.length != 0) {
$throwInternalError('requires ' + length + ' or 0 type arguments');
}
while (args.length < length) args.push($dynamic);
let value = resultMap;
for (let i = 0; i < length; i++) {
let arg = args[i];
if (arg == null) {
$throwInternalError('type arguments should not be null: '
+ $typeConstructor);
}
let map = value;
value = map.get(arg);
if (value === void 0) {
if (i + 1 == length) {
value = $typeConstructor.apply(null, args);
// Save the type constructor and arguments for reflection.
if (value) {
value[$_typeArguments] = args;
value[$_originalDeclaration] = makeGenericType;
}
map.set(arg, value);
if ($setBaseClass != null) $setBaseClass.apply(null, args);
} else {
value = new Map();
map.set(arg, value);
}
}
}
return value;
}
makeGenericType[$_genericTypeCtor] = $typeConstructor;
return makeGenericType;
})()''');
getGenericClass(type) => safeGetOwnProperty(type, _originalDeclaration);
List getGenericArgs(type) =>
JS('List', '#', safeGetOwnProperty(type, _typeArguments));
List<TypeVariable> getGenericTypeFormals(genericClass) {
return _typeFormalsFromFunction(getGenericTypeCtor(genericClass));
}
Object instantiateClass(Object genericClass, List<Object> typeArgs) {
return JS('', '#.apply(null, #)', genericClass, typeArgs);
}
final _constructorSig = JS('', 'Symbol("sigCtor")');
final _methodSig = JS('', 'Symbol("sigMethod")');
final _fieldSig = JS('', 'Symbol("sigField")');
final _getterSig = JS('', 'Symbol("sigGetter")');
final _setterSig = JS('', 'Symbol("sigSetter")');
final _staticMethodSig = JS('', 'Symbol("sigStaticMethod")');
final _staticFieldSig = JS('', 'Symbol("sigStaticField")');
final _staticGetterSig = JS('', 'Symbol("sigStaticGetter")');
final _staticSetterSig = JS('', 'Symbol("sigStaticSetter")');
final _genericTypeCtor = JS('', 'Symbol("genericType")');
final _libraryUri = JS('', 'Symbol("libraryUri")');
getConstructors(value) => _getMembers(value, _constructorSig);
getMethods(value) => _getMembers(value, _methodSig);
getFields(value) => _getMembers(value, _fieldSig);
getGetters(value) => _getMembers(value, _getterSig);
getSetters(value) => _getMembers(value, _setterSig);
getStaticMethods(value) => _getMembers(value, _staticMethodSig);
getStaticFields(value) => _getMembers(value, _staticFieldSig);
getStaticGetters(value) => _getMembers(value, _staticGetterSig);
getStaticSetters(value) => _getMembers(value, _staticSetterSig);
getGenericTypeCtor(value) => JS('', '#[#]', value, _genericTypeCtor);
/// Get the type of a method from an object using the stored signature
getType(obj) =>
JS('', '# == null ? # : #.__proto__.constructor', obj, Object, obj);
getLibraryUri(value) => JS('', '#[#]', value, _libraryUri);
setLibraryUri(f, uri) => JS('', '#[#] = #', f, _libraryUri, uri);
bool isJsInterop(obj) {
if (obj == null) return false;
if (JS('!', 'typeof # === "function"', obj)) {
// A function is a Dart function if it has runtime type information.
return JS('!', '#[#] == null', obj, _runtimeType);
}
// Primitive types are not JS interop types.
if (JS('!', 'typeof # !== "object"', obj)) return false;
// Extension types are not considered JS interop types.
// Note that it is still possible to call typed JS interop methods on
// extension types but the calls must be statically typed.
if (JS('!', '#[#] != null', obj, _extensionType)) return false;
return JS('!', '!($obj instanceof $Object)');
}
/// Get the type of a method from a type using the stored signature
getMethodType(type, name) {
var m = getMethods(type);
return m != null ? JS('', '#[#]', m, name) : null;
}
/// Gets the type of the corresponding setter (this includes writable fields).
getSetterType(type, name) {
var setters = getSetters(type);
if (setters != null) {
var type = JS('', '#[#]', setters, name);
if (type != null) {
if (JS('!', '# instanceof Array', type)) {
// The type has metadata attached. Pull out just the type.
// TODO(jmesserly): remove when we remove mirrors
return JS('', '#[0]', type);
}
return type;
}
}
var fields = getFields(type);
if (fields != null) {
var fieldInfo = JS('', '#[#]', fields, name);
if (fieldInfo != null && JS<bool>('!', '!#.isFinal', fieldInfo)) {
return JS('', '#.type', fieldInfo);
}
}
return null;
}
finalFieldType(type, metadata) =>
JS('', '{ type: #, isFinal: true, metadata: # }', type, metadata);
fieldType(type, metadata) =>
JS('', '{ type: #, isFinal: false, metadata: # }', type, metadata);
/// Get the type of a constructor from a class using the stored signature
/// If name is undefined, returns the type of the default constructor
/// Returns undefined if the constructor is not found.
classGetConstructorType(cls, name) {
if (cls == null) return null;
if (name == null) name = 'new';
var ctors = getConstructors(cls);
return ctors != null ? JS('', '#[#]', ctors, name) : null;
}
void setMethodSignature(f, sigF) => JS('', '#[#] = #', f, _methodSig, sigF);
void setFieldSignature(f, sigF) => JS('', '#[#] = #', f, _fieldSig, sigF);
void setGetterSignature(f, sigF) => JS('', '#[#] = #', f, _getterSig, sigF);
void setSetterSignature(f, sigF) => JS('', '#[#] = #', f, _setterSig, sigF);
// Set up the constructor signature field on the constructor
void setConstructorSignature(f, sigF) =>
JS('', '#[#] = #', f, _constructorSig, sigF);
// Set up the static signature field on the constructor
void setStaticMethodSignature(f, sigF) =>
JS('', '#[#] = #', f, _staticMethodSig, sigF);
void setStaticFieldSignature(f, sigF) =>
JS('', '#[#] = #', f, _staticFieldSig, sigF);
void setStaticGetterSignature(f, sigF) =>
JS('', '#[#] = #', f, _staticGetterSig, sigF);
void setStaticSetterSignature(f, sigF) =>
JS('', '#[#] = #', f, _staticSetterSig, sigF);
_getMembers(type, kind) {
var sig = JS('', '#[#]', type, kind);
return JS<bool>('!', 'typeof # == "function"', sig)
? JS('', '#[#] = #()', type, kind, sig)
: sig;
}
bool _hasMember(type, kind, name) {
var sig = _getMembers(type, kind);
return sig != null && JS<bool>('!', '# in #', name, sig);
}
bool hasMethod(type, name) => _hasMember(type, _methodSig, name);
bool hasGetter(type, name) => _hasMember(type, _getterSig, name);
bool hasSetter(type, name) => _hasMember(type, _setterSig, name);
bool hasField(type, name) => _hasMember(type, _fieldSig, name);
final _extensionType = JS('', 'Symbol("extensionType")');
final dartx = JS('', 'dartx');
/// Install properties in prototype-first order. Properties / descriptors from
/// more specific types should overwrite ones from less specific types.
void _installProperties(jsProto, dartType, installedParent) {
if (JS('!', '# === #', dartType, Object)) {
_installPropertiesForObject(jsProto);
return;
}
// If the extension methods of the parent have been installed on the parent
// of [jsProto], the methods will be available via prototype inheritance.
var dartSupertype = JS('', '#.__proto__', dartType);
if (JS('!', '# !== #', dartSupertype, installedParent)) {
_installProperties(jsProto, dartSupertype, installedParent);
}
var dartProto = JS('', '#.prototype', dartType);
copyTheseProperties(jsProto, dartProto, getOwnPropertySymbols(dartProto));
}
void _installPropertiesForObject(jsProto) {
// core.Object members need to be copied from the non-symbol name to the
// symbol name.
var coreObjProto = JS('', '#.prototype', Object);
var names = getOwnPropertyNames(coreObjProto);
for (int i = 0, n = JS('!', '#.length', names); i < n; ++i) {
var name = JS<String>('!', '#[#]', names, i);
if (name == 'constructor') continue;
var desc = getOwnPropertyDescriptor(coreObjProto, name);
defineProperty(jsProto, JS('', '#.#', dartx, name), desc);
}
}
void _installPropertiesForGlobalObject(jsProto) {
_installPropertiesForObject(jsProto);
// Use JS toString for JS objects, rather than the Dart one.
JS('', '#[dartx.toString] = function() { return this.toString(); }', jsProto);
identityEquals ??= JS('', '#[dartx._equals]', jsProto);
}
final _extensionMap = JS('', 'new Map()');
_applyExtension(jsType, dartExtType) {
// TODO(vsm): Not all registered js types are real.
if (jsType == null) return;
var jsProto = JS('', '#.prototype', jsType);
if (jsProto == null) return;
if (JS('!', '# === #', dartExtType, Object)) {
_installPropertiesForGlobalObject(jsProto);
return;
}
_installProperties(
jsProto, dartExtType, JS('', '#[#]', jsProto, _extensionType));
// Mark the JS type's instances so we can easily check for extensions.
if (JS('!', '# !== #', dartExtType, JSFunction)) {
JS('', '#[#] = #', jsProto, _extensionType, dartExtType);
}
JS('', '#[#] = #[#]', jsType, _methodSig, dartExtType, _methodSig);
JS('', '#[#] = #[#]', jsType, _fieldSig, dartExtType, _fieldSig);
JS('', '#[#] = #[#]', jsType, _getterSig, dartExtType, _getterSig);
JS('', '#[#] = #[#]', jsType, _setterSig, dartExtType, _setterSig);
}
/// Apply the previously registered extension to the type of [nativeObject].
/// This is intended for types that are not available to polyfill at startup.
applyExtension(name, nativeObject) {
var dartExtType = JS('', '#.get(#)', _extensionMap, name);
var jsType = JS('', '#.constructor', nativeObject);
_applyExtension(jsType, dartExtType);
}
/// Apply all registered extensions to a window. This is intended for
/// different frames, where registrations need to be reapplied.
applyAllExtensions(global) {
JS('', '#.forEach((dartExtType, name) => #(#[name], dartExtType))',
_extensionMap, _applyExtension, global);
}
/// Copy symbols from the prototype of the source to destination.
/// These are the only properties safe to copy onto an existing public
/// JavaScript class.
registerExtension(name, dartExtType) {
JS('', '#.set(#, #)', _extensionMap, name, dartExtType);
var jsType = JS('', '#[#]', global_, name);
_applyExtension(jsType, dartExtType);
}
///
/// Mark a concrete type as implementing extension methods.
/// For example: `class MyIter implements Iterable`.
///
/// This takes a list of names, which are the extension methods implemented.
/// It will add a forwarder, so the extension method name redirects to the
/// normal Dart method name. For example:
///
/// defineExtensionMembers(MyType, ['add', 'remove']);
///
/// Results in:
///
/// MyType.prototype[dartx.add] = MyType.prototype.add;
/// MyType.prototype[dartx.remove] = MyType.prototype.remove;
///
// TODO(jmesserly): essentially this gives two names to the same method.
// This benefit is roughly equivalent call performance either way, but the
// cost is we need to call defineExtensionMembers any time a subclass
// overrides one of these methods.
defineExtensionMethods(type, Iterable memberNames) {
var proto = JS('', '#.prototype', type);
for (var name in memberNames) {
JS('', '#[dartx.#] = #[#]', proto, name, proto, name);
}
}
/// Like [defineExtensionMethods], but for getter/setter pairs.
defineExtensionAccessors(type, Iterable memberNames) {
var proto = JS('', '#.prototype', type);
for (var name in memberNames) {
// Find the member. It should always exist (or we have a compiler bug).
var member;
var p = proto;
for (;; p = JS('', '#.__proto__', p)) {
member = getOwnPropertyDescriptor(p, name);
if (member != null) break;
}
defineProperty(proto, JS('', 'dartx[#]', name), member);
}
}
definePrimitiveHashCode(proto) {
defineProperty(proto, identityHashCode_,
getOwnPropertyDescriptor(proto, extensionSymbol('hashCode')));
}
/// Link the extension to the type it's extending as a base class.
setBaseClass(derived, base) {
JS('', '#.prototype.__proto__ = #.prototype', derived, base);
// We use __proto__ to track the superclass hierarchy (see isSubtypeOf).
JS('', '#.__proto__ = #', derived, base);
}
/// Like [setBaseClass], but for generic extension types such as `JSArray<E>`.
setExtensionBaseClass(dartType, jsType) {
// Mark the generic type as an extension type and link the prototype objects.
var dartProto = JS('', '#.prototype', dartType);
JS('', '#[#] = #', dartProto, _extensionType, dartType);
JS('', '#.__proto__ = #.prototype', dartProto, jsType);
}
/// Adds type test predicates to a class/interface type [ctor], using the
/// provided [isClass] JS Symbol.
///
/// This will operate quickly for non-generic types, native extension types,
/// as well as matching exact generic type arguments:
///
/// class C<T> {}
/// class D extends C<int> {}
/// main() { dynamic d = new D(); d as C<int>; }
///
addTypeTests(ctor, isClass) {
if (isClass == null) isClass = JS('', 'Symbol("_is_" + ctor.name)');
// TODO(jmesserly): since we know we're dealing with class/interface types,
// we can optimize this rather than go through the generic `dart.is` helpers.
JS('', '#.prototype[#] = true', ctor, isClass);
JS(
'',
'''#.is = function is_C(obj) {
return obj != null && (obj[#] || #(obj, this));
}''',
ctor,
isClass,
instanceOf);
JS(
'',
'''#.as = function as_C(obj) {
if (obj == null || obj[#]) return obj;
return #(obj, this, false);
}''',
ctor,
isClass,
cast);
JS(
'',
'''#._check = function check_C(obj) {
if (obj == null || obj[#]) return obj;
return #(obj, this, true);
}''',
ctor,
isClass,
cast);
}
// TODO(jmesserly): should we do this for all interfaces?
/// The well known symbol for testing `is Future`
final isFuture = JS('', 'Symbol("_is_Future")');
/// The well known symbol for testing `is Iterable`
final isIterable = JS('', 'Symbol("_is_Iterable")');
/// The well known symbol for testing `is List`
final isList = JS('', 'Symbol("_is_List")');
/// The well known symbol for testing `is Map`
final isMap = JS('', 'Symbol("_is_Map")');
/// The well known symbol for testing `is Stream`
final isStream = JS('', 'Symbol("_is_Stream")');
/// The well known symbol for testing `is StreamSubscription`
final isStreamSubscription = JS('', 'Symbol("_is_StreamSubscription")');
/// The default `operator ==` that calls [identical].
var identityEquals;

View file

@ -0,0 +1,271 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart._runtime;
// We need to set these properties while the sdk is only partially initialized
// so we cannot use regular Dart fields.
// The default values for these properties are set when the global_ final field
// in runtime.dart is initialized.
argumentError(value) {
throw ArgumentError.value(value);
}
throwUnimplementedError(String message) {
throw UnimplementedError(message);
}
// TODO(nshahan) Cleanup embeded strings and extract file location at runtime
// from the stacktrace.
assertFailed(String message,
[String fileUri, int line, int column, String conditionSource]) {
throw AssertionErrorImpl(message, fileUri, line, column, conditionSource);
}
throwCyclicInitializationError([Object field]) {
throw CyclicInitializationError(field);
}
throwNullValueError() {
// TODO(vsm): Per spec, we should throw an NSM here. Technically, we ought
// to thread through method info, but that uglifies the code and can't
// actually be queried ... it only affects how the error is printed.
throw NoSuchMethodError(
null, Symbol('<Unexpected Null Value>'), null, null, null);
}
castError(obj, expectedType, [@notNull bool isImplicit = false]) {
var actualType = getReifiedType(obj);
var message = _castErrorMessage(actualType, expectedType);
var error = isImplicit ? TypeErrorImpl(message) : CastErrorImpl(message);
throw error;
}
String _castErrorMessage(from, to) {
// If both types are generic classes, see if we can infer generic type
// arguments for `from` that would allow the subtype relation to work.
var fromClass = getGenericClass(from);
if (fromClass != null) {
var fromTypeFormals = getGenericTypeFormals(fromClass);
var fromType = instantiateClass(fromClass, fromTypeFormals);
var inferrer = _TypeInferrer(fromTypeFormals);
if (inferrer.trySubtypeMatch(fromType, to)) {
var inferredTypes = inferrer.getInferredTypes();
if (inferredTypes != null) {
var inferred = instantiateClass(fromClass, inferredTypes);
return "Type '${typeName(from)}' should be '${typeName(inferred)}' "
"to implement expected type '${typeName(to)}'.";
}
}
}
return "Expected a value of type '${typeName(to)}', "
"but got one of type '${typeName(from)}'";
}
/// The symbol that references the thrown Dart Object (typically but not
/// necessarily an [Error] or [Exception]), used by the [exception] function.
final Object _thrownValue = JS('', 'Symbol("_thrownValue")');
/// For a Dart [Error], this provides access to the JS Error object that
/// contains the stack trace if the error was thrown.
final Object _jsError = JS('', 'Symbol("_jsError")');
/// Gets the thrown Dart Object from an [error] caught by a JS catch.
///
/// If the throw originated in Dart, the result will typically be an [Error]
/// or [Exception], but it could be any Dart object.
///
/// If the throw originated in JavaScript, then there is not a corresponding
/// Dart value, so we just return the error object.
Object getThrown(Object error) {
if (error != null) {
// Get the Dart thrown value, if any.
var value = JS('', '#[#]', error, _thrownValue);
if (value != null) return value;
}
// Otherwise return the original object.
return error;
}
final _stackTrace = JS('', 'Symbol("_stackTrace")');
/// Returns the stack trace from an [error] caught by a JS catch.
///
/// If the throw originated in Dart, we should always have JS Error
/// (see [throw_]) so we can create a Dart [StackTrace] from that (or return a
/// previously created instance).
///
/// If the throw originated in JavaScript and was an `Error`, then we can get
/// the corresponding stack trace the same way we do for Dart throws. If the
/// throw object was not an Error, then we don't have a JS trace, so we create
/// one here.
StackTrace stackTrace(Object error) {
if (JS<bool>('!', '!(# instanceof Error)', error)) {
// We caught something that isn't a JS Error.
//
// We should only hit this path when a non-Error was thrown from JS. In
// case, there is no stack trace available, so create one here.
return _StackTrace.missing(error);
}
// If we've already created the Dart stack trace object, return it.
StackTrace trace = JS('', '#[#]', error, _stackTrace);
if (trace != null) return trace;
// Otherwise create the Dart stack trace (by parsing the JS stack), and
// cache it so we don't repeat the parsing/allocation.
return JS('', '#[#] = #', error, _stackTrace, _StackTrace(error));
}
StackTrace stackTraceForError(Error error) {
return stackTrace(JS('', '#[#]', error, _jsError));
}
/// Implements `rethrow` of [error], allowing rethrow in an expression context.
///
/// Note: [error] must be the raw JS error caught in the JS catch, not the
/// unwrapped value returned by [getThrown].
@JSExportName('rethrow')
void rethrow_(Object error) {
JS('', 'throw #', error);
}
/// Subclass of JS `Error` that wraps a thrown Dart object, and evaluates the
/// message lazily by calling `toString()` on the wrapped Dart object.
///
/// Also creates a pointer from the thrown Dart object to the JS Error
/// (via [_jsError]). This is used to implement [Error.stackTrace], but also
/// provides a way to recover the stack trace if we lose track of it.
/// [Error] requires preserving the original stack trace if an error is
/// rethrown, so we only update the pointer if it wasn't already set.
///
/// TODO(jmesserly): Dart Errors should simply be JS Errors.
final Object DartError = JS(
'!',
'''class DartError extends Error {
constructor(error) {
super();
if (error == null) error = #;
this[#] = error;
if (error != null && typeof error == "object" && error[#] == null) {
error[#] = this;
}
}
get message() {
return #(this[#]);
}
}''',
NullThrownError(),
_thrownValue,
_jsError,
_jsError,
_toString,
_thrownValue);
/// Subclass of [DartError] for cases where we're rethrowing with a different,
/// original Dart StackTrace object.
///
/// This includes the original stack trace in the JS Error message so it doesn't
/// get lost if the exception reaches JS.
final Object RethrownDartError = JS(
'!',
'''class RethrownDartError extends # {
constructor(error, stackTrace) {
super(error);
this[#] = stackTrace;
}
get message() {
return super.message + "\\n " + #(this[#]) + "\\n";
}
}''',
DartError,
_stackTrace,
_toString,
_stackTrace);
/// Implements `throw` of [exception], allowing for throw in an expression
/// context, and capturing the current stack trace.
@JSExportName('throw')
void throw_(Object exception) {
/// Wrap the object so we capture a new stack trace, and so it will print
/// nicely from JS, as if it were a normal JS error.
JS('', 'throw new #(#)', DartError, exception);
}
/// Returns a JS error for throwing the Dart [exception] Object and using the
/// provided stack [trace].
///
/// This is used by dart:async to rethrow unhandled errors in [Zone]s, and by
/// `async`/`async*` to rethrow errors from Futures/Streams into the generator
/// (so a try/catch in there can catch it).
///
/// If the exception and trace originated from the same Dart throw, then we can
/// simply return the original JS Error. Otherwise, we have to create a new JS
/// Error. The new error will have the correct Dart trace, but it will not have
/// the correct JS stack trace (visible if JavaScript ends up handling it). To
/// fix that, we use [RethrownDartError] to preserve the Dart trace and make
/// sure it gets displayed in the JS error message.
///
/// If the stack trace is null, this will preserve the original stack trace
/// on the exception, if available, otherwise it will capture the current stack
/// trace.
Object createErrorWithStack(Object exception, StackTrace trace) {
if (trace == null) {
var error = JS('', '#[#]', exception, _jsError);
return error != null ? error : JS('', 'new #(#)', DartError, exception);
}
if (trace is _StackTrace) {
/// Optimization: if this stack trace and exception already have a matching
/// Error, we can just rethrow it.
var originalError = trace._jsError;
if (identical(exception, getThrown(originalError))) {
return originalError;
}
}
return JS('', 'new #(#, #)', RethrownDartError, exception, trace);
}
// This is a utility function: it is only intended to be called from dev
// tools.
void stackPrint(Object error) {
JS('', 'console.log(#.stack ? #.stack : "No stack trace for: " + #)', error,
error, error);
}
class _StackTrace implements StackTrace {
final Object _jsError;
final Object _jsObjectMissingTrace;
String _trace;
_StackTrace(this._jsError) : _jsObjectMissingTrace = null;
_StackTrace.missing(Object caughtObj)
: _jsObjectMissingTrace = caughtObj != null ? caughtObj : 'null',
_jsError = JS('', 'Error()');
String toString() {
if (_trace != null) return _trace;
var e = _jsError;
String trace = '';
if (e != null && JS<bool>('!', 'typeof # === "object"', e)) {
trace = e is NativeError ? e.dartStack() : JS<String>('', '#.stack', e);
if (trace != null && stackTraceMapper != null) {
trace = stackTraceMapper(trace);
}
}
if (trace.isEmpty || _jsObjectMissingTrace != null) {
String jsToString;
try {
jsToString = JS('', '"" + #', _jsObjectMissingTrace);
} catch (_) {
jsToString = '<error converting JS object to string>';
}
trace = 'Non-error `$jsToString` thrown by JS does not have stack trace.'
'\nCaught in Dart at:\n\n$trace';
}
return _trace = trace;
}
}

View file

@ -0,0 +1,725 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/// This library defines runtime operations on objects used by the code
/// generator.
part of dart._runtime;
// TODO(jmesserly): remove this in favor of _Invocation.
class InvocationImpl extends Invocation {
final Symbol memberName;
final List positionalArguments;
final Map<Symbol, dynamic> namedArguments;
final List<Type> typeArguments;
final bool isMethod;
final bool isGetter;
final bool isSetter;
final String failureMessage;
InvocationImpl(memberName, List<Object> positionalArguments,
{namedArguments,
List typeArguments,
this.isMethod = false,
this.isGetter = false,
this.isSetter = false,
this.failureMessage = 'method not found'})
: memberName =
isSetter ? _setterSymbol(memberName) : _dartSymbol(memberName),
positionalArguments = List.unmodifiable(positionalArguments),
namedArguments = _namedArgsToSymbols(namedArguments),
typeArguments = typeArguments == null
? const []
: List.unmodifiable(typeArguments.map(wrapType));
static Map<Symbol, dynamic> _namedArgsToSymbols(namedArgs) {
if (namedArgs == null) return const {};
return Map.unmodifiable(Map.fromIterable(getOwnPropertyNames(namedArgs),
key: _dartSymbol, value: (k) => JS('', '#[#]', namedArgs, k)));
}
}
/// Given an object and a method name, tear off the method.
/// Sets the runtime type of the torn off method appropriately,
/// and also binds the object.
///
/// If the optional `f` argument is passed in, it will be used as the method.
/// This supports cases like `super.foo` where we need to tear off the method
/// from the superclass, not from the `obj` directly.
// TODO(leafp): Consider caching the tearoff on the object?
bind(obj, name, method) {
if (obj == null) obj = jsNull;
if (method == null) method = JS('', '#[#]', obj, name);
var f = JS('', '#.bind(#)', method, obj);
// TODO(jmesserly): canonicalize tearoffs.
JS('', '#._boundObject = #', f, obj);
JS('', '#._boundMethod = #', f, method);
JS('', '#[#] = #', f, _runtimeType, getMethodType(getType(obj), name));
return f;
}
/// Binds the `call` method of an interface type, handling null.
///
/// Essentially this works like `obj?.call`. It also handles the needs of
/// [dsend]/[dcall], returning `null` if no method was found with the given
/// canonical member [name].
///
/// [name] is typically `"call"` but it could be the [extensionSymbol] for
/// `call`, if we define it on a native type, and [obj] is known statially to be
/// a native type/interface with `call`.
bindCall(obj, name) {
if (obj == null) return null;
var ftype = getMethodType(getType(obj), name);
if (ftype == null) return null;
var method = JS('', '#[#]', obj, name);
var f = JS('', '#.bind(#)', method, obj);
// TODO(jmesserly): canonicalize tearoffs.
JS('', '#._boundObject = #', f, obj);
JS('', '#._boundMethod = #', f, method);
JS('', '#[#] = #', f, _runtimeType, ftype);
return f;
}
/// Instantiate a generic method.
///
/// We need to apply the type arguments both to the function, as well as its
/// associated function type.
gbind(f, @rest List typeArgs) {
GenericFunctionType type = JS('!', '#[#]', f, _runtimeType);
type.checkBounds(typeArgs);
// Create a JS wrapper function that will also pass the type arguments, and
// tag it with the instantiated function type.
var result =
JS('', '(...args) => #.apply(null, #.concat(args))', f, typeArgs);
return fn(result, type.instantiate(typeArgs));
}
dloadRepl(obj, field) => dload(obj, replNameLookup(obj, field), false);
// Warning: dload, dput, and dsend assume they are never called on methods
// implemented by the Object base class as those methods can always be
// statically resolved.
dload(obj, field, [@undefined mirrors]) {
if (JS('!', 'typeof # == "function" && # == "call"', obj, field)) {
return obj;
}
var f = _canonicalMember(obj, field);
trackCall(obj);
if (f != null) {
var type = getType(obj);
if (hasField(type, f) || hasGetter(type, f)) return JS('', '#[#]', obj, f);
if (hasMethod(type, f)) return bind(obj, f, null);
// Always allow for JS interop objects.
if (!JS<bool>('!', '#', mirrors) && isJsInterop(obj)) {
return JS('', '#[#]', obj, f);
}
}
return noSuchMethod(obj, InvocationImpl(field, JS('', '[]'), isGetter: true));
}
// Version of dload that matches legacy mirrors behavior for JS types.
dloadMirror(obj, field) => dload(obj, field, true);
_stripGenericArguments(type) {
var genericClass = getGenericClass(type);
if (genericClass != null) return JS('', '#()', genericClass);
return type;
}
// Version of dput that matches legacy Dart 1 type check rules and mirrors
// behavior for JS types.
// TODO(jacobr): remove the type checking rules workaround when mirrors based
// PageLoader code can generate the correct reified generic types.
dputMirror(obj, field, value) => dput(obj, field, value, true);
dputRepl(obj, field, value) =>
dput(obj, replNameLookup(obj, field), value, false);
dput(obj, field, value, [@undefined mirrors]) {
var f = _canonicalMember(obj, field);
trackCall(obj);
if (f != null) {
var setterType = getSetterType(getType(obj), f);
if (setterType != null) {
if (JS('!', '#', mirrors))
setterType = _stripGenericArguments(setterType);
return JS('', '#[#] = #._check(#)', obj, f, setterType, value);
}
// Always allow for JS interop objects.
if (!JS<bool>('!', '#', mirrors) && isJsInterop(obj)) {
return JS('', '#[#] = #', obj, f, value);
}
}
noSuchMethod(
obj, InvocationImpl(field, JS('', '[#]', value), isSetter: true));
return value;
}
/// Returns an error message if function of a given [type] can't be applied to
/// [actuals] and [namedActuals].
///
/// Returns `null` if all checks pass.
String _argumentErrors(FunctionType type, List actuals, namedActuals) {
// Check for too few required arguments.
int actualsCount = JS('!', '#.length', actuals);
var required = type.args;
int requiredCount = JS('!', '#.length', required);
if (actualsCount < requiredCount) {
return 'Dynamic call with too few arguments. '
'Expected: $requiredCount Actual: $actualsCount';
}
// Check for too many postional arguments.
var extras = actualsCount - requiredCount;
var optionals = type.optionals;
if (extras > JS<int>('!', '#.length', optionals)) {
return 'Dynamic call with too many arguments. '
'Expected: $requiredCount Actual: $actualsCount';
}
// Check if we have invalid named arguments.
Iterable names;
var named = type.named;
if (namedActuals != null) {
names = getOwnPropertyNames(namedActuals);
for (var name in names) {
if (!JS('!', '#.hasOwnProperty(#)', named, name)) {
return "Dynamic call with unexpected named argument '$name'.";
}
}
}
// Now that we know the signature matches, we can perform type checks.
for (var i = 0; i < requiredCount; ++i) {
JS('', '#[#]._check(#[#])', required, i, actuals, i);
}
for (var i = 0; i < extras; ++i) {
JS('', '#[#]._check(#[#])', optionals, i, actuals, i + requiredCount);
}
if (names != null) {
for (var name in names) {
JS('', '#[#]._check(#[#])', named, name, namedActuals, name);
}
}
return null;
}
_toSymbolName(symbol) => JS('', '''(() => {
let str = $symbol.toString();
// Strip leading 'Symbol(' and trailing ')'
return str.substring(7, str.length-1);
})()''');
_toDisplayName(name) => JS('', '''(() => {
// Names starting with _ are escaped names used to disambiguate Dart and
// JS names.
if ($name[0] === '_') {
// Inverse of
switch($name) {
case '_get':
return '[]';
case '_set':
return '[]=';
case '_negate':
return 'unary-';
case '_constructor':
case '_prototype':
return $name.substring(1);
}
}
return $name;
})()''');
Symbol _dartSymbol(name) {
return (JS<bool>('!', 'typeof # === "symbol"', name))
? JS('Symbol', '#(new #.new(#, #))', const_, PrivateSymbol,
_toSymbolName(name), name)
: JS('Symbol', '#(new #.new(#))', const_, internal.Symbol,
_toDisplayName(name));
}
Symbol _setterSymbol(name) {
return (JS<bool>('!', 'typeof # === "symbol"', name))
? JS('Symbol', '#(new #.new(# + "=", #))', const_, PrivateSymbol,
_toSymbolName(name), name)
: JS('Symbol', '#(new #.new(# + "="))', const_, internal.Symbol,
_toDisplayName(name));
}
_checkAndCall(f, ftype, obj, typeArgs, args, named, displayName) =>
JS('', '''(() => {
$trackCall($obj);
let originalTarget = obj === void 0 ? f : obj;
function callNSM(errorMessage) {
return $noSuchMethod(originalTarget, new $InvocationImpl.new(
$displayName, $args, {
namedArguments: $named,
typeArguments: $typeArgs,
isMethod: true,
failureMessage: errorMessage
}));
}
if ($f == null) return callNSM('Dynamic call of null.');
if (!($f instanceof Function)) {
// We're not a function (and hence not a method either)
// Grab the `call` method if it's not a function.
if ($f != null) {
// Getting the member succeeded, so update the originalTarget.
// (we're now trying `call()` on `f`, so we want to call its nSM rather
// than the original target's nSM).
originalTarget = f;
$f = ${bindCall(f, _canonicalMember(f, 'call'))};
$ftype = null;
$displayName = "call";
}
if ($f == null) return callNSM(
"Dynamic call of object has no instance method 'call'.");
}
// If f is a function, but not a method (no method type)
// then it should have been a function valued field, so
// get the type from the function.
if ($ftype == null) $ftype = $f[$_runtimeType];
if ($ftype == null) {
// TODO(leafp): Allow JS objects to go through?
if ($typeArgs != null) {
// TODO(jmesserly): is there a sensible way to handle these?
$throwTypeError('call to JS object `' + $obj +
'` with type arguments <' + $typeArgs + '> is not supported.');
}
if ($named != null) $args.push($named);
return $f.apply($obj, $args);
}
// TODO(vsm): Remove when we no longer need mirrors metadata.
// An array is used to encode annotations attached to the type.
if ($ftype instanceof Array) $ftype = $ftype[0];
// Apply type arguments
if ($ftype instanceof $GenericFunctionType) {
let formalCount = $ftype.formalCount;
if ($typeArgs == null) {
$typeArgs = $ftype.instantiateDefaultBounds();
} else if ($typeArgs.length != formalCount) {
return callNSM('Dynamic call with incorrect number of type arguments. ' +
'Expected: ' + formalCount + ' Actual: ' + $typeArgs.length);
} else {
$ftype.checkBounds($typeArgs);
}
$ftype = $ftype.instantiate($typeArgs);
} else if ($typeArgs != null) {
return callNSM('Dynamic call with unexpected type arguments. ' +
'Expected: 0 Actual: ' + $typeArgs.length);
}
let errorMessage = $_argumentErrors($ftype, $args, $named);
if (errorMessage == null) {
if ($typeArgs != null) $args = $typeArgs.concat($args);
if ($named != null) $args.push($named);
return $f.apply($obj, $args);
}
return callNSM(errorMessage);
})()''');
dcall(f, args, [@undefined named]) => _checkAndCall(
f, null, JS('', 'void 0'), null, args, named, JS('', 'f.name'));
dgcall(f, typeArgs, args, [@undefined named]) =>
_checkAndCall(f, null, JS('', 'void 0'), typeArgs, args, named, 'call');
/// Helper for REPL dynamic invocation variants that make a best effort to
/// enable accessing private members across library boundaries.
replNameLookup(object, field) => JS('', '''(() => {
let rawField = $field;
if (typeof(field) == 'symbol') {
// test if the specified field exists in which case it is safe to use it.
if ($field in $object) return $field;
// Symbol is from a different library. Make a best effort to
$field = $field.toString();
$field = $field.substring('Symbol('.length, field.length - 1);
} else if ($field.charAt(0) != '_') {
// Not a private member so default call path is safe.
return $field;
}
// If the exact field name is present, invoke callback with it.
if ($field in $object) return $field;
// TODO(jacobr): warn if there are multiple private members with the same
// name which could happen if super classes in different libraries have
// the same private member name.
let proto = $object;
while (proto !== null) {
// Private field (indicated with "_").
let symbols = Object.getOwnPropertySymbols(proto);
let target = 'Symbol(' + $field + ')';
for (let s = 0; s < symbols.length; s++) {
let sym = symbols[s];
if (target == sym.toString()) return sym;
}
proto = proto.__proto__;
}
// We didn't find a plausible alternate private symbol so just fall back
// to the regular field.
return rawField;
})()''');
/// Shared code for dsend, dindex, and dsetindex.
callMethod(obj, name, typeArgs, args, named, displayName) {
if (JS('!', 'typeof # == "function" && # == "call"', obj, name)) {
return dgcall(obj, typeArgs, args, named);
}
var symbol = _canonicalMember(obj, name);
if (symbol == null) {
return noSuchMethod(obj, InvocationImpl(displayName, args, isMethod: true));
}
var f = obj != null ? JS('', '#[#]', obj, symbol) : null;
var type = getType(obj);
var ftype = getMethodType(type, symbol);
// No such method if dart object and ftype is missing.
return _checkAndCall(f, ftype, obj, typeArgs, args, named, displayName);
}
dsend(obj, method, args, [@undefined named]) =>
callMethod(obj, method, null, args, named, method);
dgsend(obj, typeArgs, method, args, [@undefined named]) =>
callMethod(obj, method, typeArgs, args, named, method);
dsendRepl(obj, method, args, [@undefined named]) =>
callMethod(obj, replNameLookup(obj, method), null, args, named, method);
dgsendRepl(obj, typeArgs, method, args, [@undefined named]) =>
callMethod(obj, replNameLookup(obj, method), typeArgs, args, named, method);
dindex(obj, index) => callMethod(obj, '_get', null, [index], null, '[]');
dsetindex(obj, index, value) =>
callMethod(obj, '_set', null, [index, value], null, '[]=');
@notNull
@JSExportName('is')
bool instanceOf(obj, type) {
if (obj == null) {
return identical(type, unwrapType(Null)) || _isTop(type);
}
return isSubtypeOf(getReifiedType(obj), type);
}
@JSExportName('as')
cast(obj, type, @notNull bool isImplicit) {
if (obj == null) return obj;
var actual = getReifiedType(obj);
if (isSubtypeOf(actual, type)) {
return obj;
}
return castError(obj, type, isImplicit);
}
bool test(bool obj) {
if (obj == null) _throwBooleanConversionError();
return obj;
}
bool dtest(obj) {
if (obj is! bool) booleanConversionFailed(obj);
return obj;
}
void _throwBooleanConversionError() => throw BooleanConversionAssertionError();
void booleanConversionFailed(obj) {
var actual = typeName(getReifiedType(test(obj)));
throw TypeErrorImpl("type '$actual' is not a 'bool' in boolean expression");
}
asInt(obj) {
if (obj == null) return null;
if (JS('!', 'Math.floor(#) != #', obj, obj)) {
castError(obj, JS('', '#', int), false);
}
return obj;
}
/// Checks that `x` is not null or undefined.
//
// TODO(jmesserly): inline this, either by generating it as a function into
// the module, or via some other pattern such as:
//
// <expr> || nullErr()
// (t0 = <expr>) != null ? t0 : nullErr()
@JSExportName('notNull')
_notNull(x) {
if (x == null) throwNullValueError();
return x;
}
/// The global constant map table.
final constantMaps = JS('', 'new Map()');
// TODO(leafp): This table gets quite large in apps.
// Keeping the paths is probably expensive. It would probably
// be more space efficient to just use a direct hash table with
// an appropriately defined structural equality function.
Object _lookupNonTerminal(Object map, Object key) {
var result = JS('', '#.get(#)', map, key);
if (result != null) return result;
JS('', '#.set(#, # = new Map())', map, key, result);
return result;
}
Map<K, V> constMap<K, V>(JSArray elements) {
var count = elements.length;
var map = _lookupNonTerminal(constantMaps, count);
for (var i = 0; i < count; i++) {
map = _lookupNonTerminal(map, JS('', '#[#]', elements, i));
}
map = _lookupNonTerminal(map, K);
var result = JS('', '#.get(#)', map, V);
if (result != null) return result;
result = ImmutableMap<K, V>.from(elements);
JS('', '#.set(#, #)', map, V, result);
return result;
}
final constantSets = JS('', 'new Map()');
var _immutableSetConstructor;
// We cannot invoke private class constructors directly in Dart.
Set<E> _createImmutableSet<E>(JSArray<E> elements) {
_immutableSetConstructor ??=
JS('', '#.#', getLibrary('dart:collection'), '_ImmutableSet\$');
return JS('', 'new (#(#)).from(#)', _immutableSetConstructor, E, elements);
}
Set<E> constSet<E>(JSArray<E> elements) {
var count = elements.length;
var map = _lookupNonTerminal(constantSets, count);
for (var i = 0; i < count; i++) {
map = _lookupNonTerminal(map, JS('', '#[#]', elements, i));
}
var result = JS('', '#.get(#)', map, E);
if (result != null) return result;
result = _createImmutableSet<E>(elements);
JS('', '#.set(#, #)', map, E, result);
return result;
}
bool dassert(value) {
if (JS('!', '# != null && #[#] instanceof #', value, value, _runtimeType,
AbstractFunctionType)) {
value = dcall(value, []);
}
return dtest(value);
}
final _value = JS('', 'Symbol("_value")');
///
/// Looks up a sequence of [keys] in [map], recursively, and
/// returns the result. If the value is not found, [valueFn] will be called to
/// add it. For example:
///
/// let map = new Map();
/// putIfAbsent(map, [1, 2, 'hi ', 'there '], () => 'world');
///
/// ... will create a Map with a structure like:
///
/// { 1: { 2: { 'hi ': { 'there ': 'world' } } } }
///
multiKeyPutIfAbsent(map, keys, valueFn) => JS('', '''(() => {
for (let k of $keys) {
let value = $map.get(k);
if (!value) {
// TODO(jmesserly): most of these maps are very small (e.g. 1 item),
// so it may be worth optimizing for that.
$map.set(k, value = new Map());
}
$map = value;
}
if ($map.has($_value)) return $map.get($_value);
let value = $valueFn();
$map.set($_value, value);
return value;
})()''');
/// The global constant table.
/// This maps the number of names in the object (n)
/// to a path of length 2*n of maps indexed by the name and
/// and value of the field. The final map is
/// indexed by runtime type, and contains the canonical
/// version of the object.
final constants = JS('', 'new Map()');
///
/// Canonicalize a constant object.
///
/// Preconditions:
/// - `obj` is an objects or array, not a primitive.
/// - nested values of the object are themselves already canonicalized.
///
@JSExportName('const')
const_(obj) => JS('', '''(() => {
let names = $getOwnNamesAndSymbols($obj);
let count = names.length;
// Index by count. All of the paths through this map
// will have 2*count length.
let map = $_lookupNonTerminal($constants, count);
// TODO(jmesserly): there's no guarantee in JS that names/symbols are
// returned in the same order.
//
// We could probably get the same order if we're judicious about
// initializing fields in a consistent order across all const constructors.
// Alternatively we need a way to sort them to make consistent.
//
// Right now we use the (name,value) pairs in sequence, which prevents
// an object with incorrect field values being returned, but won't
// canonicalize correctly if key order is different.
//
// See issue https://github.com/dart-lang/sdk/issues/30876
for (let i = 0; i < count; i++) {
let name = names[i];
map = $_lookupNonTerminal(map, name);
map = $_lookupNonTerminal(map, $obj[name]);
}
// TODO(leafp): It may be the case that the reified type
// is always one of the keys already used above?
let type = $getReifiedType($obj);
let value = map.get(type);
if (value) return value;
map.set(type, $obj);
return $obj;
})()''');
/// The global constant list table.
/// This maps the number of elements in the list (n)
/// to a path of length n of maps indexed by the value
/// of the field. The final map is indexed by the element
/// type and contains the canonical version of the list.
final constantLists = JS('', 'new Map()');
/// Canonicalize a constant list
constList(elements, elementType) => JS('', '''(() => {
let count = $elements.length;
let map = $_lookupNonTerminal($constantLists, count);
for (let i = 0; i < count; i++) {
map = $_lookupNonTerminal(map, elements[i]);
}
let value = map.get($elementType);
if (value) return value;
${getGenericClass(JSArray)}($elementType).unmodifiable($elements);
map.set($elementType, elements);
return elements;
})()''');
constFn(x) => JS('', '() => x');
/// Gets the extension symbol given a member [name].
///
/// This is inlined by the compiler when used with a literal string.
extensionSymbol(String name) => JS('', 'dartx[#]', name);
// The following are helpers for Object methods when the receiver
// may be null. These should only be generated by the compiler.
bool equals(x, y) {
// We handle `y == null` inside our generated operator methods, to keep this
// function minimal.
// This pattern resulted from performance testing; it found that dispatching
// was the fastest solution, even for primitive types.
return JS('!', '# == null ? # == null : #[#](#)', x, y, x,
extensionSymbol('_equals'), y);
}
int hashCode(obj) {
return obj == null ? 0 : JS('!', '#[#]', obj, extensionSymbol('hashCode'));
}
@JSExportName('toString')
String _toString(obj) {
if (obj == null) return "null";
if (obj is String) return obj;
return JS('!', '#[#]()', obj, extensionSymbol('toString'));
}
/// Converts to a non-null [String], equivalent to
/// `dart.notNull(dart.toString(obj))`.
///
/// This is commonly used in string interpolation.
@notNull
String str(obj) {
if (obj == null) return "null";
if (obj is String) return obj;
return _notNull(JS('!', '#[#]()', obj, extensionSymbol('toString')));
}
// TODO(jmesserly): is the argument type verified statically?
noSuchMethod(obj, Invocation invocation) {
if (obj == null) defaultNoSuchMethod(obj, invocation);
return JS('', '#[#](#)', obj, extensionSymbol('noSuchMethod'), invocation);
}
/// The default implementation of `noSuchMethod` to match `Object.noSuchMethod`.
defaultNoSuchMethod(obj, Invocation i) {
throw NoSuchMethodError.withInvocation(obj, i);
}
runtimeType(obj) {
return obj == null ? Null : JS('', '#[dartx.runtimeType]', obj);
}
final identityHashCode_ = JS('', 'Symbol("_identityHashCode")');
/// Adapts a Dart `get iterator` into a JS `[Symbol.iterator]`.
// TODO(jmesserly): instead of an adaptor, we could compile Dart iterators
// natively implementing the JS iterator protocol. This would allow us to
// optimize them a bit.
final JsIterator = JS('', '''
class JsIterator {
constructor(dartIterator) {
this.dartIterator = dartIterator;
}
next() {
let i = this.dartIterator;
let done = !i.moveNext();
return { done: done, value: done ? void 0 : i.current };
}
}
''');
_canonicalMember(obj, name) {
// Private names are symbols and are already canonical.
if (JS('!', 'typeof # === "symbol"', name)) return name;
if (obj != null && JS<bool>('!', '#[#] != null', obj, _extensionType)) {
return JS('', 'dartx.#', name);
}
// Check for certain names that we can't use in JS
if (JS('!', '# == "constructor" || # == "prototype"', name, name)) {
JS('', '# = "+" + #', name, name);
}
return name;
}
/// Emulates the implicit "loadLibrary" function provided by a deferred library.
///
/// Libraries are not actually deferred in DDC, so this just returns a future
/// that completes immediately.
Future loadLibrary() => Future.value();
/// Defines lazy statics.
void defineLazy(to, from) {
for (var name in getOwnNamesAndSymbols(from)) {
defineLazyField(to, name, getOwnPropertyDescriptor(from, name));
}
}

View file

@ -0,0 +1,222 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/// This library defines the association between runtime objects and
/// runtime types.
part of dart._runtime;
/// Runtime type information. This module defines the mapping from
/// runtime objects to their runtime type information. See the types
/// module for the definition of how type information is represented.
///
/// There are two kinds of objects that represent "types" at runtime. A
/// "runtime type" contains all of the data needed to implement the runtime
/// type checking inserted by the compiler. These objects fall into four
/// categories:
///
/// - Things represented by javascript primitives, such as
/// null, numbers, booleans, strings, and symbols. For these
/// we map directly from the javascript type (given by typeof)
/// to the appropriate class type from core, which serves as their
/// rtti.
///
/// - Functions, which are represented by javascript functions.
/// Representations of Dart functions always have a
/// _runtimeType property attached to them with the appropriate
/// rtti.
///
/// - Objects (instances) which are represented by instances of
/// javascript (ES6) classes. Their types are given by their
/// classes, and the rtti is accessed by projecting out their
/// constructor field.
///
/// - Types objects, which are represented as described in the types
/// module. Types always have a _runtimeType property attached to
/// them with the appropriate rtti. The rtti for these is always
/// core.Type. TODO(leafp): consider the possibility that we can
/// reliably recognize type objects and map directly to core.Type
/// rather than attaching this property everywhere.
///
/// The other kind of object representing a "type" is the instances of the
/// dart:core Type class. These are the user visible objects you get by calling
/// "runtimeType" on an object or using a class literal expression. These are
/// different from the above objects, and are created by calling `wrapType()`
/// on a runtime type.
/// Tag a closure with a type.
///
/// `dart.fn(closure, type)` marks [closure] with the provided runtime [type].
fn(closure, type) {
JS('', '#[#] = #', closure, _runtimeType, type);
return closure;
}
/// Tag a closure with a type that's computed lazily.
///
/// `dart.fn(closure, type)` marks [closure] with a getter that uses
/// [computeType] to return the runtime type.
///
/// The getter/setter replaces the property with a value property, so the
/// resulting function is compatible with [fn] and the type can be set again
/// safely.
lazyFn(closure, Object Function() computeType) {
defineAccessor(closure, _runtimeType,
get: () => defineValue(closure, _runtimeType, computeType()),
set: (value) => defineValue(closure, _runtimeType, value),
configurable: true);
return closure;
}
// TODO(vsm): How should we encode the runtime type?
final _runtimeType = JS('', 'Symbol("_runtimeType")');
final _moduleName = JS('', 'Symbol("_moduleName")');
getFunctionType(obj) {
// TODO(vsm): Encode this properly on the function for Dart-generated code.
var args = JS<List>('!', 'Array(#.length).fill(#)', obj, dynamic);
return fnType(bottom, args, JS('', 'void 0'));
}
/// Returns the runtime representation of the type of obj.
///
/// The resulting object is used internally for runtime type checking. This is
/// different from the user-visible Type object returned by calling
/// `runtimeType` on some Dart object.
getReifiedType(obj) {
switch (JS<String>('!', 'typeof #', obj)) {
case "object":
if (obj == null) return JS('', '#', Null);
if (JS('!', '# instanceof #', obj, Object)) {
return JS('', '#.constructor', obj);
}
var result = JS('', '#[#]', obj, _extensionType);
if (result == null) return JS('', '#', jsobject);
return result;
case "function":
// All Dart functions and callable classes must set _runtimeType
var result = JS('', '#[#]', obj, _runtimeType);
if (result != null) return result;
return JS('', '#', jsobject);
case "undefined":
return JS('', '#', Null);
case "number":
return JS('', 'Math.floor(#) == # ? # : #', obj, obj, int, double);
case "boolean":
return JS('', '#', bool);
case "string":
return JS('', '#', String);
case "symbol":
default:
return JS('', '#', jsobject);
}
}
/// Return the module name for a raw library object.
String getModuleName(Object module) => JS('', '#[#]', module, _moduleName);
final _loadedModules = JS('', 'new Map()');
final _loadedPartMaps = JS('', 'new Map()');
final _loadedSourceMaps = JS('', 'new Map()');
List<String> getModuleNames() {
return JSArray<String>.of(JS('', 'Array.from(#.keys())', _loadedModules));
}
String getSourceMap(String moduleName) {
return JS('!', '#.get(#)', _loadedSourceMaps, moduleName);
}
/// Return all library objects in the specified module.
getModuleLibraries(String name) {
var module = JS('', '#.get(#)', _loadedModules, name);
if (module == null) return null;
JS('', '#[#] = #', module, _moduleName, name);
return module;
}
/// Return the part map for a specific module.
getModulePartMap(String name) => JS('', '#.get(#)', _loadedPartMaps, name);
/// Track all libraries
void trackLibraries(
String moduleName, Object libraries, Object parts, String sourceMap) {
if (parts is String) {
// Added for backwards compatibility.
// package:build_web_compilers currently invokes this without [parts]
// in its bootstrap code.
sourceMap = parts as String;
parts = JS('', '{}');
}
JS('', '#.set(#, #)', _loadedSourceMaps, moduleName, sourceMap);
JS('', '#.set(#, #)', _loadedModules, moduleName, libraries);
JS('', '#.set(#, #)', _loadedPartMaps, moduleName, parts);
}
List<String> _libraries;
Map<String, Object> _libraryObjects;
Map<String, List<String>> _parts;
_computeLibraryMetadata() {
_libraries = [];
_libraryObjects = {};
_parts = {};
var modules = getModuleNames();
for (var name in modules) {
// Add libraries from each module.
var module = getModuleLibraries(name);
var libraries = getOwnPropertyNames(module).cast<String>();
_libraries.addAll(libraries);
for (var library in libraries) {
_libraryObjects[library] = JS('', '#.#', module, library);
}
// Add parts from each module.
var partMap = getModulePartMap(name);
libraries = getOwnPropertyNames(partMap).cast<String>();
for (var library in libraries) {
_parts[library] = List.from(JS('List', '#.#', partMap, library));
}
}
}
/// Returns the JS library object for a given library [uri] or
/// undefined / null if it isn't loaded. Top-level types and
/// methods are available on this object.
Object getLibrary(String uri) {
if (_libraryObjects == null) {
_computeLibraryMetadata();
}
return _libraryObjects[uri];
}
/// Returns a JSArray of library uris (e.g,
/// ['dart:core', 'dart:_internal', ..., 'package:foo/bar.dart', ... 'main.dart'])
/// loaded in this application.
List<String> getLibraries() {
if (_libraries == null) {
_computeLibraryMetadata();
}
return _libraries;
}
/// Returns a JSArray of part uris for a given [libraryUri].
/// The part uris will be relative to the [libraryUri].
///
/// E.g., invoking `getParts('package:intl/intl.dart')` returns (as of this
/// writing): ```
/// ["src/intl/bidi_formatter.dart", "src/intl/bidi_utils.dart",
/// "src/intl/compact_number_format.dart", "src/intl/date_format.dart",
/// "src/intl/date_format_field.dart", "src/intl/date_format_helpers.dart",
/// "src/intl/number_format.dart"]
/// ```
///
/// If [libraryUri] doesn't map to a library or maps to a library with no
/// parts, an empty list is returned.
List<String> getParts(String libraryUri) {
if (_parts == null) {
_computeLibraryMetadata();
}
return _parts[libraryUri] ?? [];
}

View file

@ -0,0 +1,210 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
@ReifyFunctionTypes(false)
library dart._runtime;
import 'dart:async';
import 'dart:collection';
import 'dart:_debugger' show stackTraceMapper, trackCall;
import 'dart:_foreign_helper' show JS, JSExportName, rest, spread;
import 'dart:_interceptors' show JSArray, jsNull, JSFunction, NativeError;
import 'dart:_internal' as internal show Symbol;
import 'dart:_js_helper'
show
AssertionErrorImpl,
BooleanConversionAssertionError,
CastErrorImpl,
DartIterator,
TypeErrorImpl,
JsLinkedHashMap,
ImmutableMap,
PrivateSymbol,
ReifyFunctionTypes,
NoReifyGeneric,
notNull,
undefined;
export 'dart:_debugger' show getDynamicStats, clearDynamicStats, trackCall;
part 'utils.dart';
part 'classes.dart';
part 'rtti.dart';
part 'types.dart';
part 'errors.dart';
part 'operations.dart';
// TODO(vsm): Move polyfill code to dart:html.
// Note, native extensions are registered onto types in dart.global.
// This polyfill needs to run before the corresponding dart:html code is run.
final _polyfilled = JS('', 'Symbol("_polyfilled")');
bool polyfill(window) => JS('', '''(() => {
if ($window[$_polyfilled]) return false;
$window[$_polyfilled] = true;
if (typeof $window.NodeList !== "undefined") {
// TODO(vsm): Do we still need these?
$window.NodeList.prototype.get = function(i) { return this[i]; };
$window.NamedNodeMap.prototype.get = function(i) { return this[i]; };
$window.DOMTokenList.prototype.get = function(i) { return this[i]; };
$window.HTMLCollection.prototype.get = function(i) { return this[i]; };
// Expose constructors for DOM types dart:html needs to assume are
// available on window.
if (typeof $window.PannerNode == "undefined") {
let audioContext;
if (typeof $window.AudioContext == "undefined" &&
(typeof $window.webkitAudioContext != "undefined")) {
audioContext = new $window.webkitAudioContext();
} else {
audioContext = new $window.AudioContext();
$window.StereoPannerNode =
audioContext.createStereoPanner().constructor;
}
$window.PannerNode = audioContext.createPanner().constructor;
}
if (typeof $window.AudioSourceNode == "undefined") {
$window.AudioSourceNode = MediaElementAudioSourceNode.__proto__;
}
if (typeof $window.FontFaceSet == "undefined") {
// CSS Font Loading is not supported on Edge.
if (typeof $window.document.fonts != "undefined") {
$window.FontFaceSet = $window.document.fonts.__proto__.constructor;
}
}
if (typeof $window.MemoryInfo == "undefined") {
if (typeof $window.performance.memory != "undefined") {
$window.MemoryInfo = $window.performance.memory.constructor;
}
}
if (typeof $window.Geolocation == "undefined") {
$window.Geolocation == $window.navigator.geolocation.constructor;
}
if (typeof $window.Animation == "undefined") {
let d = $window.document.createElement('div');
if (typeof d.animate != "undefined") {
$window.Animation = d.animate(d).constructor;
}
}
if (typeof $window.SourceBufferList == "undefined") {
if ('MediaSource' in $window) {
$window.SourceBufferList =
new $window.MediaSource().sourceBuffers.constructor;
}
}
if (typeof $window.SpeechRecognition == "undefined") {
$window.SpeechRecognition = $window.webkitSpeechRecognition;
$window.SpeechRecognitionError = $window.webkitSpeechRecognitionError;
$window.SpeechRecognitionEvent = $window.webkitSpeechRecognitionEvent;
}
}
return true;
})()''');
@JSExportName('global')
final global_ = JS('', '''
function () {
// Find global object.
var globalState = (typeof window != "undefined") ? window
: (typeof global != "undefined") ? global
: (typeof self != "undefined") ? self : null;
if (!globalState) {
// Some platforms (e.g., d8) do not define any of the above. The
// following is a non-CSP safe way to access the global object:
globalState = new Function('return this;')();
}
$polyfill(globalState);
// By default, stack traces cutoff at 10. Set the limit to Infinity for
// better debugging.
if (globalState.Error) {
globalState.Error.stackTraceLimit = Infinity;
}
// These settings must be configured before the application starts so that
// user code runs with the correct configuration.
let settings = 'ddcSettings' in globalState ? globalState.ddcSettings : {};
$trackProfile(
'trackProfile' in settings ? settings.trackProfile : false);
return globalState;
}()
''');
void trackProfile(bool flag) {
JS('', 'dart.__trackProfile = #', flag);
}
final JsSymbol = JS('', 'Symbol');
/// The prototype used for all Dart libraries.
///
/// This makes it easy to identify Dart library objects, and also improves
/// performance (JS engines such as V8 tend to assume `Object.create(null)` is
/// used for a Map, so they don't optimize it as they normally would for
/// class-like objects).
///
/// The `dart.library` field is set by the compiler during SDK bootstrapping
/// (because it is needed for dart:_runtime itself), so we don't need to
/// initialize it here. The name `dart.library` is used because it reads nicely,
/// for example:
///
/// const my_library = Object.create(dart.library);
///
Object libraryPrototype = JS('', 'dart.library');
// TODO(vsm): Remove once this flag we've removed the ability to
// whitelist / fallback on the old behavior.
bool startAsyncSynchronously = true;
void setStartAsyncSynchronously([bool value = true]) {
startAsyncSynchronously = value;
}
/// A list of all JS Maps used for caching results, such as by [isSubtypeOf] and
/// [generic].
///
/// This is used by [hotRestart] to ensure we don't leak types from previous
/// libraries.
@notNull
final List<Object> _cacheMaps = JS('!', '[]');
/// A list of functions to reset static fields back to their uninitialized
/// state.
///
/// This is populated by [defineLazyField], and only contains the list of fields
/// that have actually been initialized.
@notNull
final List<void Function()> _resetFields = JS('', '[]');
/// Clears out runtime state in `dartdevc` so we can hot-restart.
///
/// This should be called when the user requests a hot-restart, when the UI is
/// handling that user action.
void hotRestart() {
// TODO(jmesserly): we need to prevent all pending callbacks from firing.
for (var f in _resetFields) f();
_resetFields.clear();
for (var m in _cacheMaps) JS('', '#.clear()', m);
_cacheMaps.clear();
JS('', '#.clear()', constantMaps);
}
/// Marks enqueuing an async operation.
///
/// This will be called by library code when enqueuing an async operation
/// controlled by the JavaScript event handler.
///
/// It will also call [removeAsyncCallback] when Dart callback is about to be
/// executed (note this is called *before* the callback executes, so more
/// async operations could be added from that).
void Function() addAsyncCallback = JS('', 'function() {}');
/// Marks leaving a javascript async operation.
///
/// See [addAsyncCallback].
void Function() removeAsyncCallback = JS('', 'function() {}');

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,136 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart._runtime;
/// This library defines a set of general javascript utilities for us
/// by the Dart runtime.
// TODO(ochafik): Rewrite some of these in Dart when possible.
final Function(Object, Object, Object) defineProperty =
JS('', 'Object.defineProperty');
defineValue(obj, name, value) {
defineAccessor(obj, name, value: value, configurable: true, writable: true);
return value;
}
final Function(Object, Object,
{Object get,
Object set,
Object value,
bool configurable,
bool writable}) defineAccessor = JS('', 'Object.defineProperty');
final Function(Object, Object) getOwnPropertyDescriptor =
JS('', 'Object.getOwnPropertyDescriptor');
final Iterable Function(Object) getOwnPropertyNames =
JS('', 'Object.getOwnPropertyNames');
final Function(Object) getOwnPropertySymbols =
JS('', 'Object.getOwnPropertySymbols');
final Function(Object) getPrototypeOf = JS('', 'Object.getPrototypeOf');
/// This error indicates a strong mode specific failure, other than a type
/// assertion failure (TypeError) or CastError.
void throwTypeError(String message) {
throw TypeErrorImpl(message);
}
/// This error indicates a bug in the runtime or the compiler.
void throwInternalError(String message) {
JS('', 'throw Error(#)', message);
}
Iterable getOwnNamesAndSymbols(obj) {
var names = getOwnPropertyNames(obj);
var symbols = getOwnPropertySymbols(obj);
return JS('', '#.concat(#)', names, symbols);
}
safeGetOwnProperty(obj, name) {
var desc = getOwnPropertyDescriptor(obj, name);
if (desc != null) return JS('', '#.value', desc);
}
/// Defines a lazy static field.
/// After initial get or set, it will replace itself with a value property.
// TODO(jmesserly): reusing descriptor objects has been shown to improve
// performance in other projects (e.g. webcomponents.js ShadowDOM polyfill).
defineLazyField(to, name, desc) => JS('', '''(() => {
const initializer = $desc.get;
let init = initializer;
let value = null;
$desc.get = function() {
if (init == null) return value;
let f = init;
init = $throwCyclicInitializationError;
if (f === init) f($name); // throw cycle error
// On the first (non-cyclic) execution, record the field so we can reset it
// later if needed (hot restart).
$_resetFields.push(() => {
init = initializer;
value = null;
});
// Try to evaluate the field, using try+catch to ensure we implement the
// correct Dart error semantics.
try {
value = f();
init = null;
return value;
} catch (e) {
init = null;
value = null;
throw e;
}
};
$desc.configurable = true;
if ($desc.set != null) {
$desc.set = function(x) {
init = null;
value = x;
};
}
return ${defineProperty(to, name, desc)};
})()''');
copyTheseProperties(to, from, names) {
for (int i = 0, n = JS('!', '#.length', names); i < n; ++i) {
var name = JS('', '#[#]', names, i);
if (name == 'constructor') continue;
copyProperty(to, from, name);
}
return to;
}
copyProperty(to, from, name) {
var desc = getOwnPropertyDescriptor(from, name);
if (JS('!', '# == Symbol.iterator', name)) {
// On native types, Symbol.iterator may already be present.
// TODO(jmesserly): investigate if we still need this.
// If so, we need to find a better solution.
// See https://github.com/dart-lang/sdk/issues/28324
var existing = getOwnPropertyDescriptor(to, name);
if (existing != null) {
if (JS('!', '#.writable', existing)) {
JS('', '#[#] = #.value', to, name, desc);
}
return;
}
}
defineProperty(to, name, desc);
}
@JSExportName('export')
exportProperty(to, from, name) => copyProperty(to, from, name);
/// Copy properties from source to destination object.
/// This operation is commonly called `mixin` in JS.
copyProperties(to, from) {
return copyTheseProperties(to, from, getOwnNamesAndSymbols(from));
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,285 @@
// 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 dart._foreign_helper;
/**
* Emits a JavaScript code fragment parameterized by arguments.
*
* Hash characters `#` in the [codeTemplate] are replaced in left-to-right order
* with expressions that contain the values of, or evaluate to, the arguments.
* The number of hash marks must match the number or arguments. Although
* declared with arguments [arg0] through [arg2], the form actually has no limit
* on the number of arguments.
*
* The [typeDescription] argument is interpreted as a description of the
* behavior of the JavaScript code. Currently it describes the types that may
* be returned by the expression, with the additional behavior that the returned
* values may be fresh instances of the types. The type information must be
* correct as it is trusted by the compiler in optimizations, and it must be
* precise as possible since it is used for native live type analysis to
* tree-shake large parts of the DOM libraries. If poorly written, the
* [typeDescription] will cause unnecessarily bloated programs. (You can check
* for this by compiling with `--verbose`; there is an info message describing
* the number of native (DOM) types that can be removed, which usually should be
* greater than zero.)
*
* The [typeDescription] is a [String] which contains a union of types separated
* by vertical bar `|` symbols, e.g. `"num|String"` describes the union of
* numbers and Strings. There is no type in Dart that is this precise. The
* Dart alternative would be `Object` or `dynamic`, but these types imply that
* the JS-code might also be creating instances of all the DOM types. If `null`
* is possible, it must be specified explicitly, e.g. `"String|Null"`.
* [typeDescription] has several extensions to help describe the behavior more
* accurately. In addition to the union type already described:
*
* + `=Object` is a plain JavaScript object. Some DOM methods return instances
* that have no corresponding Dart type (e.g. cross-frame documents),
* `=Object` can be used to describe these untyped' values.
*
* + `var` (or empty string). If the entire [typeDescription] is `var` (or
* empty string) then the type is `dynamic` but the code is known to not
* create any instances.
*
* Examples:
*
* // Parent window might be an opaque cross-frame window.
* var thing = JS('=Object|Window', '#.parent', myWindow);
*
* Guidelines:
*
* + Do not use any parameter, local, method or field names in the
* [codeTemplate]. These names are all subject to arbitrary renaming by the
* compiler. Pass the values in via `#` substition, and test with the
* `--minify` dart2js command-line option.
*
* + The substituted expressions are values, not locations.
*
* JS('void', '# += "x"', this.field);
*
* `this.field` might not be a substituted as a reference to the field. The
* generated code might accidentally work as intended, but it also might be
*
* var t1 = this.field;
* t1 += "x";
*
* or
*
* this.get$field() += "x";
*
* The remedy in this case is to expand the `+=` operator, leaving all
* references to the Dart field as Dart code:
*
* this.field = JS<String>('!', '# + "x"', this.field);
*
* + Never use `#` in function bodies.
*
* This is a variation on the previous guideline. Since `#` is replaced with
* an *expression* and the expression is only valid in the immediate context,
* `#` should never appear in a function body. Doing so might defer the
* evaluation of the expression, and its side effects, until the function is
* called.
*
* For example,
*
* var value = foo();
* var f = JS('', 'function(){return #}', value)
*
* might result in no immediate call to `foo` and a call to `foo` on every
* call to the JavaScript function bound to `f`. This is better:
*
* var f = JS('',
* '(function(val) { return function(){return val}; })(#)', value);
*
* Since `#` occurs in the immediately evaluated expression, the expression
* is immediately evaluated and bound to `val` in the immediate call.
*
*
* Additional notes.
*
* In the future we may extend [typeDescription] to include other aspects of the
* behavior, for example, separating the returned types from the instantiated
* types, or including effects to allow the compiler to perform more
* optimizations around the code. This might be an extension of [JS] or a new
* function similar to [JS] with additional arguments for the new information.
*/
// Add additional optional arguments if needed. The method is treated internally
// as a variable argument method.
T JS<T extends Object>(String typeDescription, String codeTemplate,
[arg0,
arg1,
arg2,
arg3,
arg4,
arg5,
arg6,
arg7,
arg8,
arg9,
arg10,
arg11,
arg12,
arg13,
arg14,
arg15,
arg16,
arg17,
arg18,
arg19]) {}
/// Annotates the compiled Js name for fields and methods.
/// Similar behaviour to `JS` from `package:js/js.dart` (but usable from runtime
/// files), and not to be confused with `JSName` from `js_helper` (which deals
/// with names of externs).
// TODO(jmesserly): remove this in favor of js_helper's `@JSName`
// (Currently they have slightly different semantics, but they can be unified.)
class JSExportName {
final String name;
const JSExportName(this.name);
}
/**
* Returns the JavaScript constructor function for Dart's Object class.
* This can be used for type tests, as in
*
* if (JS<bool>('!', '# instanceof #', obj, JS_DART_OBJECT_CONSTRUCTOR()))
* ...
*/
JS_DART_OBJECT_CONSTRUCTOR() {}
/**
* Returns the interceptor for class [type]. The interceptor is the type's
* constructor's `prototype` property. [type] will typically be the class, not
* an interface, e.g. `JS_INTERCEPTOR_CONSTANT(JSInt)`, not
* `JS_INTERCEPTOR_CONSTANT(int)`.
*/
JS_INTERCEPTOR_CONSTANT(Type type) {}
/**
* Returns the prefix used for generated is checks on classes.
*/
String JS_OPERATOR_IS_PREFIX() {}
/**
* Returns the prefix used for generated type argument substitutions on classes.
*/
String JS_OPERATOR_AS_PREFIX() {}
/// Returns the name of the class `Object` in the generated code.
String JS_OBJECT_CLASS_NAME() {}
/// Returns the name of the class `Null` in the generated code.
String JS_NULL_CLASS_NAME() {}
/// Returns the name of the class `Function` in the generated code.
String JS_FUNCTION_CLASS_NAME() {}
/**
* Returns the field name used for determining if an object or its
* interceptor has JavaScript indexing behavior.
*/
String JS_IS_INDEXABLE_FIELD_NAME() {}
/// Returns the name used for generated function types on classes and methods.
String JS_SIGNATURE_NAME() {}
/// Returns the name used to tag typedefs.
String JS_TYPEDEF_TAG() {}
/// Returns the name used to tag function type representations in JavaScript.
String JS_FUNCTION_TYPE_TAG() {}
/**
* Returns the name used to tag void return in function type representations
* in JavaScript.
*/
String JS_FUNCTION_TYPE_VOID_RETURN_TAG() {}
/**
* Returns the name used to tag return types in function type representations
* in JavaScript.
*/
String JS_FUNCTION_TYPE_RETURN_TYPE_TAG() {}
/**
* Returns the name used to tag required parameters in function type
* representations in JavaScript.
*/
String JS_FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG() {}
/**
* Returns the name used to tag optional parameters in function type
* representations in JavaScript.
*/
String JS_FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG() {}
/**
* Returns the name used to tag named parameters in function type
* representations in JavaScript.
*/
String JS_FUNCTION_TYPE_NAMED_PARAMETERS_TAG() {}
/// Returns the JS name for [name] from the Namer.
String JS_GET_NAME(String name) {}
/// Returns the state of a flag that is determined by the state of the compiler
/// when the program has been analyzed.
bool JS_GET_FLAG(String name) {}
/**
* Pretend [code] is executed. Generates no executable code. This is used to
* model effects at some other point in external code. For example, the
* following models an assignment to foo with an unknown value.
*
* var foo;
*
* main() {
* JS_EFFECT((_){ foo = _; })
* }
*
* TODO(sra): Replace this hack with something to mark the volatile or
* externally initialized elements.
*/
void JS_EFFECT(Function code) {
code(null);
}
/**
* Use this class for creating constants that hold JavaScript code.
* For example:
*
* const constant = JS_CONST('typeof window != "undefined");
*
* This code will generate:
* $.JS_CONST_1 = typeof window != "undefined";
*/
class JS_CONST {
final String code;
const JS_CONST(this.code);
}
/**
* JavaScript string concatenation. Inputs must be Strings. Corresponds to the
* HStringConcat SSA instruction and may be constant-folded.
*/
String JS_STRING_CONCAT(String a, String b) {
// This body is unused, only here for type analysis.
return JS<String>('!', '# + #', a, b);
}
/// Same `@rest` annotation and `spread` function as in
/// `package:js/src/varargs.dart`.
///
/// Runtime files cannot import packages, which is why we have an ad-hoc copy.
class _Rest {
const _Rest();
}
const _Rest rest = _Rest();
dynamic spread(args) {
throw StateError('The spread function cannot be called, '
'it should be compiled away.');
}

View file

@ -0,0 +1,137 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart._js_helper;
class IdentityMap<K, V> extends InternalMap<K, V> {
final _map = JS('', 'new Map()');
// We track the number of modifications done to the key set of the
// hash map to be able to throw when the map is modified while being
// iterated over.
//
// Value cycles after 2^30 modifications so that modification counts are
// always unboxed (Smi) values. Modification detection will be missed if you
// make exactly some multiple of 2^30 modifications between advances of an
// iterator.
@notNull
int _modifications = 0;
IdentityMap();
IdentityMap.from(JSArray entries) {
var map = _map;
for (int i = 0, n = JS<int>('!', '#.length', entries); i < n; i += 2) {
JS('', '#.set(#[#], #[#])', map, entries, i, entries, i + 1);
}
}
int get length => JS<int>('!', '#.size', _map);
bool get isEmpty => JS<bool>('!', '#.size == 0', _map);
bool get isNotEmpty => JS<bool>('!', '#.size != 0', _map);
Iterable<K> get keys => _JSMapIterable<K>(this, true);
Iterable<V> get values => _JSMapIterable<V>(this, false);
bool containsKey(Object key) {
return JS<bool>('!', '#.has(#)', _map, key);
}
bool containsValue(Object value) {
for (var v in JS('', '#.values()', _map)) {
if (v == value) return true;
}
return false;
}
void addAll(Map<K, V> other) {
if (other.isNotEmpty) {
var map = _map;
other.forEach((key, value) {
JS('', '#.set(#, #)', map, key, value);
});
_modifications = (_modifications + 1) & 0x3ffffff;
}
}
V operator [](Object key) {
V value = JS('', '#.get(#)', _map, key);
return value == null ? null : value; // coerce undefined to null.
}
void operator []=(K key, V value) {
var map = _map;
int length = JS('!', '#.size', map);
JS('', '#.set(#, #)', map, key, value);
if (length != JS<int>('!', '#.size', map)) {
_modifications = (_modifications + 1) & 0x3ffffff;
}
}
V putIfAbsent(K key, V ifAbsent()) {
if (JS<bool>('!', '#.has(#)', _map, key)) {
return JS('', '#.get(#)', _map, key);
}
V value = ifAbsent();
if (value == null) value = null; // coerce undefined to null.
JS('', '#.set(#, #)', _map, key, value);
_modifications = (_modifications + 1) & 0x3ffffff;
return value;
}
V remove(Object key) {
V value = JS('', '#.get(#)', _map, key);
if (JS<bool>('!', '#.delete(#)', _map, key)) {
_modifications = (_modifications + 1) & 0x3ffffff;
}
return value == null ? null : value; // coerce undefined to null.
}
void clear() {
if (JS<int>('!', '#.size', _map) > 0) {
JS('', '#.clear()', _map);
_modifications = (_modifications + 1) & 0x3ffffff;
}
}
}
class _JSMapIterable<E> extends EfficientLengthIterable<E> {
final InternalMap _map;
@notNull
final bool _isKeys;
_JSMapIterable(this._map, this._isKeys);
int get length => _map.length;
bool get isEmpty => _map.isEmpty;
@JSExportName('Symbol.iterator')
_jsIterator() {
var map = _map;
var iterator =
JS('', '# ? #.keys() : #.values()', _isKeys, map._map, map._map);
int modifications = map._modifications;
return JS(
'',
'''{
next() {
if (# != #) {
throw #;
}
return #.next();
}
}''',
modifications,
map._modifications,
ConcurrentModificationError(map),
iterator);
}
Iterator<E> get iterator => DartIterator<E>(_jsIterator());
bool contains(Object element) =>
_isKeys ? _map.containsKey(element) : _map.containsValue(element);
void forEach(void f(E element)) {
for (var entry in this) f(entry);
}
}

View file

@ -0,0 +1,233 @@
// 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 dart._interceptors;
import 'dart:collection';
import 'dart:_internal' hide Symbol;
import 'dart:_js_helper';
import 'dart:_foreign_helper' show JS, JSExportName;
import 'dart:math' show Random, ln2;
import 'dart:_runtime' as dart;
part 'js_array.dart';
part 'js_number.dart';
part 'js_string.dart';
// TODO(jmesserly): remove, this doesn't do anything for us.
abstract class Interceptor {
const Interceptor();
// Use native JS toString method instead of standard Dart Object.toString.
String toString() => JS<String>('!', '#.toString()', this);
}
// TODO(jmesserly): remove
getInterceptor(obj) => obj;
/**
* The interceptor class for [bool].
*/
@JsPeerInterface(name: 'Boolean')
class JSBool extends Interceptor implements bool {
const JSBool();
// Note: if you change this, also change the function [S].
@notNull
String toString() => JS<String>('!', r'String(#)', this);
// The values here are SMIs, co-prime and differ about half of the bit
// positions, including the low bit, so they are different mod 2^k.
@notNull
int get hashCode => this ? (2 * 3 * 23 * 3761) : (269 * 811);
@notNull
bool operator &(@nullCheck bool other) =>
JS<bool>('!', "# && #", other, this);
@notNull
bool operator |(@nullCheck bool other) =>
JS<bool>('!', "# || #", other, this);
@notNull
bool operator ^(@nullCheck bool other) => !identical(this, other);
Type get runtimeType => bool;
}
/**
* The supertype for JSString and JSArray. Used by the backend as to
* have a type mask that contains the objects that we can use the
* native JS [] operator and length on.
*/
abstract class JSIndexable<E> {
int get length;
E operator [](int index);
}
/**
* The interface implemented by JavaScript objects. These are methods in
* addition to the regular Dart Object methods like [Object.hashCode].
*
* This is the type that should be exported by a JavaScript interop library.
*/
abstract class JSObject {}
/**
* Interceptor base class for JavaScript objects not recognized as some more
* specific native type.
*/
abstract class JavaScriptObject extends Interceptor implements JSObject {
const JavaScriptObject();
// It would be impolite to stash a property on the object.
int get hashCode => 0;
Type get runtimeType => JSObject;
}
/**
* Interceptor for plain JavaScript objects created as JavaScript object
* literals or `new Object()`.
*/
class PlainJavaScriptObject extends JavaScriptObject {
const PlainJavaScriptObject();
}
/**
* Interceptor for unclassified JavaScript objects, typically objects with a
* non-trivial prototype chain.
*
* This class also serves as a fallback for unknown JavaScript exceptions.
*/
class UnknownJavaScriptObject extends JavaScriptObject {
const UnknownJavaScriptObject();
String toString() => JS<String>('!', 'String(#)', this);
}
class NativeError extends Interceptor {
String dartStack() => JS<String>('!', '#.stack', this);
}
// Note that this needs to be in interceptors.dart in order for
// it to be picked up as an extension type.
@JsPeerInterface(name: 'TypeError')
class JSNoSuchMethodError extends NativeError implements NoSuchMethodError {
static final _nullError = RegExp(r"^Cannot read property '(.+)' of null$");
static final _notAFunction = RegExp(r"^(.+) is not a function$");
static final _extensionName = RegExp(r"^Symbol\(dartx\.(.+)\)$");
static final _privateName = RegExp(r"^Symbol\((_.+)\)$");
String _fieldName(String message) {
var match = _nullError.firstMatch(message);
if (match == null) return null;
var name = match[1];
match = _extensionName.firstMatch(name) ?? _privateName.firstMatch(name);
return match != null ? match[1] : name;
}
String _functionCallTarget(String message) {
var match = _notAFunction.firstMatch(message);
return match != null ? match[1] : null;
}
String dartStack() {
var stack = super.dartStack();
// Strip TypeError from first line.
stack = toString() + '\n' + stack.split('\n').sublist(1).join('\n');
return stack;
}
StackTrace get stackTrace => dart.stackTrace(this);
String toString() {
String message = JS('!', '#.message', this);
var callTarget = _functionCallTarget(message);
if (callTarget != null) {
return "NoSuchMethodError: tried to call a non-function, such as null: "
"'$callTarget'";
}
// TODO(vsm): Distinguish between null reference errors and other
// TypeErrors. We should not get non-null TypeErrors from DDC code,
// but we may from native JavaScript.
var name = _fieldName(message);
if (name == null) {
// Not a Null NSM error: fallback to JS.
return JS<String>('!', '#.toString()', this);
}
return "NoSuchMethodError: invalid member on null: '$name'";
}
}
@JsPeerInterface(name: 'Function')
class JSFunction extends Interceptor {
toString() {
// If the function is a Type object, we should just display the type name.
//
// Regular Dart code should typically get wrapped type objects instead of
// raw type (aka JS constructor) objects, however raw type objects can be
// exposed to Dart code via JS interop or debugging tools.
if (dart.isType(this)) return dart.typeName(this);
return JS<String>('!', r'"Closure: " + # + " from: " + #',
dart.typeName(dart.getReifiedType(this)), this);
}
// TODO(jmesserly): remove these once we canonicalize tearoffs.
operator ==(other) {
if (other == null) return false;
var boundObj = JS<Object>('', '#._boundObject', this);
if (boundObj == null) return JS<bool>('!', '# === #', this, other);
return JS(
'bool',
'# === #._boundObject && #._boundMethod === #._boundMethod',
boundObj,
other,
this,
other);
}
get hashCode {
var boundObj = JS<Object>('', '#._boundObject', this);
if (boundObj == null) return identityHashCode(this);
var boundMethod = JS<Object>('!', '#._boundMethod', this);
int hash = (17 * 31 + boundObj.hashCode) & 0x1fffffff;
return (hash * 31 + identityHashCode(boundMethod)) & 0x1fffffff;
}
get runtimeType => dart.wrapType(dart.getReifiedType(this));
}
/// A class used for implementing `null` tear-offs.
class JSNull {
toString() => 'null';
noSuchMethod(Invocation i) => dart.defaultNoSuchMethod(null, i);
}
final Object jsNull = JSNull();
// Note that this needs to be in interceptors.dart in order for
// it to be picked up as an extension type.
@JsPeerInterface(name: 'RangeError')
class JSRangeError extends Interceptor implements ArgumentError {
StackTrace get stackTrace => dart.stackTrace(this);
get invalidValue => null;
get name => null;
get message => JS<String>('!', '#.message', this);
String toString() => "Invalid argument: $message";
}
// Obsolete in dart dev compiler. Added only so that the same version of
// dart:html can be used in dart2js an dev compiler.
// Warning: calls to these methods need to be removed before custom elements
// and cross-frame dom objects behave correctly in ddc.
// See https://github.com/dart-lang/sdk/issues/28326
findInterceptorConstructorForType(Type type) {}
findConstructorForNativeSubclassType(Type type, String name) {}
getNativeInterceptor(object) {}
setDispatchProperty(object, value) {}

View file

@ -0,0 +1,101 @@
// 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 dart._isolate_helper;
import 'dart:_runtime' as dart;
import 'dart:async';
import 'dart:_foreign_helper' show JS;
/// Deprecated way of initializing `main()` in DDC, typically called from JS.
@deprecated
void startRootIsolate(main, args) {
if (args == null) args = <String>[];
if (args is List) {
if (args is! List<String>) args = List<String>.from(args);
// DDC attaches signatures only when torn off, and the typical way of
// getting `main` via the JS ABI won't do this. So use JS to invoke main.
if (JS<bool>('!', 'typeof # == "function"', main)) {
// JS will ignore extra arguments.
JS('', '#(#, #)', main, args, null);
} else {
// Not a function. Use a dynamic call to throw an error.
(main as dynamic)(args);
}
} else {
throw ArgumentError("Arguments to main must be a List: $args");
}
}
// TODO(vsm): Other libraries import global from here. Consider replacing
// those uses to just refer to the one in dart:runtime.
final global = dart.global_;
class TimerImpl implements Timer {
final bool _once;
int _handle;
int _tick = 0;
TimerImpl(int milliseconds, void callback()) : _once = true {
if (hasTimer()) {
void internalCallback() {
_handle = null;
dart.removeAsyncCallback();
_tick = 1;
callback();
}
dart.addAsyncCallback();
_handle = JS(
'int', '#.setTimeout(#, #)', global, internalCallback, milliseconds);
} else {
throw UnsupportedError("`setTimeout()` not found.");
}
}
TimerImpl.periodic(int milliseconds, void callback(Timer timer))
: _once = false {
if (hasTimer()) {
dart.addAsyncCallback();
int start = JS<int>('!', 'Date.now()');
_handle = JS<int>('!', '#.setInterval(#, #)', global, () {
int tick = this._tick + 1;
if (milliseconds > 0) {
int duration = JS<int>('!', 'Date.now()') - start;
if (duration > (tick + 1) * milliseconds) {
tick = duration ~/ milliseconds;
}
}
this._tick = tick;
callback(this);
}, milliseconds);
} else {
throw UnsupportedError("Periodic timer.");
}
}
int get tick => _tick;
void cancel() {
if (hasTimer()) {
if (_handle == null) return;
dart.removeAsyncCallback();
if (_once) {
JS('void', '#.clearTimeout(#)', global, _handle);
} else {
JS('void', '#.clearInterval(#)', global, _handle);
}
_handle = null;
} else {
throw UnsupportedError("Canceling a timer.");
}
}
bool get isActive => _handle != null;
}
bool hasTimer() {
return JS('', '#.setTimeout', global) != null;
}

View file

@ -0,0 +1,694 @@
// 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.
part of dart._interceptors;
/**
* The interceptor class for [List]. The compiler recognizes this
* class as an interceptor, and changes references to [:this:] to
* actually use the receiver of the method, which is generated as an extra
* argument added to each member.
*/
@JsPeerInterface(name: 'Array')
class JSArray<E> implements List<E>, JSIndexable<E> {
const JSArray();
/**
* Constructor for adding type parameters to an existing JavaScript
* Array. Used for creating literal lists.
*/
factory JSArray.of(list) {
// TODO(sra): Move this to core.List for better readability.
//
// TODO(jmesserly): this uses special compiler magic to close over the
// parameterized ES6 'JSArray' class.
JS('', '#.__proto__ = JSArray.prototype', list);
return JS('-dynamic', '#', list);
}
// TODO(jmesserly): consider a fixed array subclass instead.
factory JSArray.fixed(list) {
JS('', '#.__proto__ = JSArray.prototype', list);
JS('', r'#.fixed$length = Array', list);
return JS('-dynamic', '#', list);
}
factory JSArray.unmodifiable(list) {
JS('', '#.__proto__ = JSArray.prototype', list);
JS('', r'#.fixed$length = Array', list);
JS('', r'#.immutable$list = Array', list);
return JS('-dynamic', '#', list);
}
static void markFixedList(list) {
// Functions are stored in the hidden class and not as properties in
// the object. We never actually look at the value, but only want
// to know if the property exists.
JS('', r'#.fixed$length = Array', list);
}
static void markUnmodifiableList(list) {
// Functions are stored in the hidden class and not as properties in
// the object. We never actually look at the value, but only want
// to know if the property exists.
JS('', r'#.fixed$length = Array', list);
JS('', r'#.immutable$list = Array', list);
}
checkMutable(reason) {
if (JS<bool>('!', r'#.immutable$list', this)) {
throw UnsupportedError(reason);
}
}
checkGrowable(reason) {
if (JS<bool>('!', r'#.fixed$length', this)) {
throw UnsupportedError(reason);
}
}
List<R> cast<R>() => List.castFrom<E, R>(this);
void add(E value) {
checkGrowable('add');
JS('void', r'#.push(#)', this, value);
}
E removeAt(@nullCheck int index) {
checkGrowable('removeAt');
if (index < 0 || index >= length) {
throw RangeError.value(index);
}
return JS('-dynamic', r'#.splice(#, 1)[0]', this, index);
}
void insert(@nullCheck int index, E value) {
checkGrowable('insert');
if (index < 0 || index > length) {
throw RangeError.value(index);
}
JS('void', r'#.splice(#, 0, #)', this, index, value);
}
void insertAll(@nullCheck int index, Iterable<E> iterable) {
checkGrowable('insertAll');
RangeError.checkValueInInterval(index, 0, this.length, "index");
if (iterable is! EfficientLengthIterable) {
iterable = iterable.toList();
}
@nullCheck
int insertionLength = iterable.length;
this.length += insertionLength;
int end = index + insertionLength;
this.setRange(end, this.length, this, index);
this.setRange(index, end, iterable);
}
void setAll(@nullCheck int index, Iterable<E> iterable) {
checkMutable('setAll');
RangeError.checkValueInInterval(index, 0, this.length, "index");
for (var element in iterable) {
this[index++] = element;
}
}
E removeLast() {
checkGrowable('removeLast');
if (length == 0) throw diagnoseIndexError(this, -1);
return JS('var', r'#.pop()', this);
}
bool remove(Object element) {
checkGrowable('remove');
var length = this.length;
for (int i = 0; i < length; i++) {
if (this[i] == element) {
JS('var', r'#.splice(#, 1)', this, i);
return true;
}
}
return false;
}
/**
* Removes elements matching [test] from [this] List.
*/
void removeWhere(bool test(E element)) {
checkGrowable('removeWhere');
_removeWhere(test, true);
}
void retainWhere(bool test(E element)) {
checkGrowable('retainWhere');
_removeWhere(test, false);
}
void _removeWhere(bool test(E element), bool removeMatching) {
// Performed in two steps, to avoid exposing an inconsistent state
// to the [test] function. First the elements to retain are found, and then
// the original list is updated to contain those elements.
// TODO(sra): Replace this algorithm with one that retains a list of ranges
// to be removed. Most real uses remove 0, 1 or a few clustered elements.
List retained = [];
int end = this.length;
for (int i = 0; i < end; i++) {
// TODO(22407): Improve bounds check elimination to allow this JS code to
// be replaced by indexing.
E element = JS('-dynamic', '#[#]', this, i);
// !test() ensures bool conversion in checked mode.
if (!test(element) == removeMatching) {
retained.add(element);
}
if (this.length != end) throw ConcurrentModificationError(this);
}
if (retained.length == end) return;
this.length = retained.length;
@nullCheck
var length = retained.length;
for (int i = 0; i < length; i++) {
JS('', '#[#] = #[#]', this, i, retained, i);
}
}
Iterable<E> where(bool f(E element)) {
return WhereIterable<E>(this, f);
}
Iterable<T> expand<T>(Iterable<T> f(E element)) {
return ExpandIterable<E, T>(this, f);
}
void addAll(Iterable<E> collection) {
int i = this.length;
checkGrowable('addAll');
for (E e in collection) {
assert(i == this.length || (throw ConcurrentModificationError(this)));
i++;
JS('void', r'#.push(#)', this, e);
}
}
void clear() {
length = 0;
}
void forEach(void f(E element)) {
int end = this.length;
for (int i = 0; i < end; i++) {
// TODO(22407): Improve bounds check elimination to allow this JS code to
// be replaced by indexing.
var/*=E*/ element = JS('', '#[#]', this, i);
f(element);
if (this.length != end) throw ConcurrentModificationError(this);
}
}
Iterable<T> map<T>(T f(E element)) {
return MappedListIterable<E, T>(this, f);
}
String join([String separator = ""]) {
var length = this.length;
var list = List(length);
for (int i = 0; i < length; i++) {
list[i] = "${this[i]}";
}
return JS<String>('!', "#.join(#)", list, separator);
}
Iterable<E> take(int n) {
return SubListIterable<E>(this, 0, n);
}
Iterable<E> takeWhile(bool test(E value)) {
return TakeWhileIterable<E>(this, test);
}
Iterable<E> skip(int n) {
return SubListIterable<E>(this, n, null);
}
Iterable<E> skipWhile(bool test(E value)) {
return SkipWhileIterable<E>(this, test);
}
E reduce(E combine(E previousValue, E element)) {
int length = this.length;
if (length == 0) throw IterableElementError.noElement();
E value = this[0];
for (int i = 1; i < length; i++) {
// TODO(22407): Improve bounds check elimination to allow this JS code to
// be replaced by indexing.
var/*=E*/ element = JS('', '#[#]', this, i);
value = combine(value, element);
if (length != this.length) throw ConcurrentModificationError(this);
}
return value;
}
T fold<T>(T initialValue, T combine(T previousValue, E element)) {
var value = initialValue;
int length = this.length;
for (int i = 0; i < length; i++) {
// TODO(22407): Improve bounds check elimination to allow this JS code to
// be replaced by indexing.
var/*=E*/ element = JS('', '#[#]', this, i);
value = combine(value, element);
if (this.length != length) throw ConcurrentModificationError(this);
}
return value;
}
E firstWhere(bool test(E value), {E orElse()}) {
int end = this.length;
for (int i = 0; i < end; ++i) {
// TODO(22407): Improve bounds check elimination to allow this JS code to
// be replaced by indexing.
var/*=E*/ element = JS('', '#[#]', this, i);
if (test(element)) return element;
if (this.length != end) throw ConcurrentModificationError(this);
}
if (orElse != null) return orElse();
throw IterableElementError.noElement();
}
E lastWhere(bool test(E element), {E orElse()}) {
int length = this.length;
for (int i = length - 1; i >= 0; i--) {
// TODO(22407): Improve bounds check elimination to allow this JS code to
// be replaced by indexing.
var/*=E*/ element = JS('', '#[#]', this, i);
if (test(element)) return element;
if (length != this.length) {
throw ConcurrentModificationError(this);
}
}
if (orElse != null) return orElse();
throw IterableElementError.noElement();
}
E singleWhere(bool test(E element), {E orElse()}) {
int length = this.length;
E match = null;
bool matchFound = false;
for (int i = 0; i < length; i++) {
// TODO(22407): Improve bounds check elimination to allow this JS code to
// be replaced by indexing.
E element = JS('-dynamic', '#[#]', this, i);
if (test(element)) {
if (matchFound) {
throw IterableElementError.tooMany();
}
matchFound = true;
match = element;
}
if (length != this.length) {
throw ConcurrentModificationError(this);
}
}
if (matchFound) return match;
if (orElse != null) return orElse();
throw IterableElementError.noElement();
}
E elementAt(int index) {
return this[index];
}
List<E> sublist(@nullCheck int start, [int end]) {
if (start < 0 || start > length) {
throw RangeError.range(start, 0, length, "start");
}
if (end == null) {
end = length;
} else {
@notNull
var _end = end;
if (_end < start || _end > length) {
throw RangeError.range(end, start, length, "end");
}
}
if (start == end) return <E>[];
return JSArray<E>.of(JS('', r'#.slice(#, #)', this, start, end));
}
Iterable<E> getRange(int start, int end) {
RangeError.checkValidRange(start, end, this.length);
return SubListIterable<E>(this, start, end);
}
E get first {
if (length > 0) return this[0];
throw IterableElementError.noElement();
}
E get last {
if (length > 0) return this[length - 1];
throw IterableElementError.noElement();
}
E get single {
if (length == 1) return this[0];
if (length == 0) throw IterableElementError.noElement();
throw IterableElementError.tooMany();
}
void removeRange(@nullCheck int start, @nullCheck int end) {
checkGrowable('removeRange');
RangeError.checkValidRange(start, end, this.length);
int deleteCount = end - start;
JS('', '#.splice(#, #)', this, start, deleteCount);
}
void setRange(@nullCheck int start, @nullCheck int end, Iterable<E> iterable,
[@nullCheck int skipCount = 0]) {
checkMutable('set range');
RangeError.checkValidRange(start, end, this.length);
int length = end - start;
if (length == 0) return;
RangeError.checkNotNegative(skipCount, "skipCount");
List<E> otherList;
int otherStart = 0;
// TODO(floitsch): Make this accept more.
if (iterable is List<E>) {
otherList = iterable;
otherStart = skipCount;
} else {
otherList = iterable.skip(skipCount).toList(growable: false);
otherStart = 0;
}
if (otherStart + length > otherList.length) {
throw IterableElementError.tooFew();
}
if (otherStart < start) {
// Copy backwards to ensure correct copy if [from] is this.
// TODO(sra): If [from] is the same Array as [this], we can copy without
// type annotation checks on the stores.
for (int i = length - 1; i >= 0; i--) {
// Use JS to avoid bounds check (the bounds check elimination
// optimzation is too weak). The 'E' type annotation is a store type
// check - we can't rely on iterable, it could be List<dynamic>.
E element = otherList[otherStart + i];
JS('', '#[#] = #', this, start + i, element);
}
} else {
for (int i = 0; i < length; i++) {
E element = otherList[otherStart + i];
JS('', '#[#] = #', this, start + i, element);
}
}
}
void fillRange(@nullCheck int start, @nullCheck int end, [E fillValue]) {
checkMutable('fill range');
RangeError.checkValidRange(start, end, this.length);
for (int i = start; i < end; i++) {
// Store is safe since [fillValue] type has been checked as parameter.
JS('', '#[#] = #', this, i, fillValue);
}
}
void replaceRange(
@nullCheck int start, @nullCheck int end, Iterable<E> replacement) {
checkGrowable('replace range');
RangeError.checkValidRange(start, end, this.length);
if (replacement is! EfficientLengthIterable) {
replacement = replacement.toList();
}
int removeLength = end - start;
@nullCheck
int insertLength = replacement.length;
if (removeLength >= insertLength) {
int delta = removeLength - insertLength;
int insertEnd = start + insertLength;
int newLength = this.length - delta;
this.setRange(start, insertEnd, replacement);
if (delta != 0) {
this.setRange(insertEnd, newLength, this, end);
this.length = newLength;
}
} else {
int delta = insertLength - removeLength;
int newLength = this.length + delta;
int insertEnd = start + insertLength; // aka. end + delta.
this.length = newLength;
this.setRange(insertEnd, newLength, this, end);
this.setRange(start, insertEnd, replacement);
}
}
bool any(bool test(E element)) {
int end = this.length;
for (int i = 0; i < end; i++) {
// TODO(22407): Improve bounds check elimination to allow this JS code to
// be replaced by indexing.
var/*=E*/ element = JS('', '#[#]', this, i);
if (test(element)) return true;
if (this.length != end) throw ConcurrentModificationError(this);
}
return false;
}
bool every(bool test(E element)) {
int end = this.length;
for (int i = 0; i < end; i++) {
// TODO(22407): Improve bounds check elimination to allow this JS code to
// be replaced by indexing.
E element = JS('-dynamic', '#[#]', this, i);
if (!test(element)) return false;
if (this.length != end) throw ConcurrentModificationError(this);
}
return true;
}
Iterable<E> get reversed => ReversedListIterable<E>(this);
void sort([int compare(E a, E b)]) {
checkMutable('sort');
if (compare == null) {
Sort.sort(this, (a, b) => Comparable.compare(a, b));
} else {
Sort.sort(this, compare);
}
}
void shuffle([Random random]) {
checkMutable('shuffle');
if (random == null) random = Random();
int length = this.length;
while (length > 1) {
int pos = random.nextInt(length);
length -= 1;
var tmp = this[length];
this[length] = this[pos];
this[pos] = tmp;
}
}
int indexOf(Object element, [@nullCheck int start = 0]) {
int length = this.length;
if (start >= length) {
return -1;
}
if (start < 0) {
start = 0;
}
for (int i = start; i < length; i++) {
if (this[i] == element) {
return i;
}
}
return -1;
}
int lastIndexOf(Object element, [int _startIndex]) {
@notNull
int startIndex = _startIndex ?? this.length - 1;
if (startIndex >= this.length) {
startIndex = this.length - 1;
} else if (startIndex < 0) {
return -1;
}
for (int i = startIndex; i >= 0; i--) {
if (this[i] == element) {
return i;
}
}
return -1;
}
bool contains(Object other) {
var length = this.length;
for (int i = 0; i < length; i++) {
E element = JS('Null', '#[#]', this, i);
if (element == other) return true;
}
return false;
}
@notNull
bool get isEmpty => length == 0;
@notNull
bool get isNotEmpty => !isEmpty;
String toString() => ListBase.listToString(this);
List<E> toList({@nullCheck bool growable = true}) {
var list = JS('', '#.slice()', this);
if (!growable) markFixedList(list);
return JSArray<E>.of(list);
}
Set<E> toSet() => Set<E>.from(this);
Iterator<E> get iterator => ArrayIterator<E>(this);
int get hashCode => identityHashCode(this);
@notNull
bool operator ==(other) => identical(this, other);
@notNull
int get length => JS<int>('!', r'#.length', this);
void set length(@nullCheck int newLength) {
checkGrowable('set length');
// TODO(sra): Remove this test and let JavaScript throw an error.
if (newLength < 0) {
throw RangeError.range(newLength, 0, null, 'newLength');
}
// JavaScript with throw a RangeError for numbers that are too big. The
// message does not contain the value.
JS('void', r'#.length = #', this, newLength);
}
E operator [](int index) {
// Suppress redundant null checks via JS.
if (index == null ||
JS<int>('!', '#', index) >= JS<int>('!', '#.length', this) ||
JS<int>('!', '#', index) < 0) {
throw diagnoseIndexError(this, index);
}
return JS('var', '#[#]', this, index);
}
void operator []=(int index, E value) {
checkMutable('indexed set');
if (index == null ||
JS<int>('!', '#', index) >= JS<int>('!', '#.length', this) ||
JS<int>('!', '#', index) < 0) {
throw diagnoseIndexError(this, index);
}
JS('void', r'#[#] = #', this, index, value);
}
Map<int, E> asMap() {
return ListMapView<E>(this);
}
Type get runtimeType =>
dart.wrapType(JS('', '#(#)', dart.getGenericClass(List), E));
Iterable<E> followedBy(Iterable<E> other) =>
FollowedByIterable<E>.firstEfficient(this, other);
Iterable<T> whereType<T>() => new WhereTypeIterable<T>(this);
List<E> operator +(List<E> other) {
int totalLength = this.length + other.length;
return <E>[]
..length = totalLength
..setRange(0, this.length, this)
..setRange(this.length, totalLength, other);
}
int indexWhere(bool test(E element), [int start = 0]) {
if (start >= this.length) return -1;
if (start < 0) start = 0;
for (int i = start; i < this.length; i++) {
if (test(this[i])) return i;
}
return -1;
}
int lastIndexWhere(bool test(E element), [int start]) {
if (start == null) start = this.length - 1;
if (start < 0) return -1;
for (int i = start; i >= 0; i--) {
if (test(this[i])) return i;
}
return -1;
}
void set first(E element) {
if (this.isEmpty) throw RangeError.index(0, this);
this[0] = element;
}
void set last(E element) {
if (this.isEmpty) throw RangeError.index(0, this);
this[this.length - 1] = element;
}
}
/**
* Dummy subclasses that allow the backend to track more precise
* information about arrays through their type. The CPA type inference
* relies on the fact that these classes do not override [] nor []=.
*
* These classes are really a fiction, and can have no methods, since
* getInterceptor always returns JSArray. We should consider pushing the
* 'isGrowable' and 'isMutable' checks into the getInterceptor implementation so
* these classes can have specialized implementations. Doing so will challenge
* many assumptions in the JS backend.
*/
class JSMutableArray<E> extends JSArray<E> {}
class JSFixedArray<E> extends JSMutableArray<E> {}
class JSExtendableArray<E> extends JSMutableArray<E> {}
class JSUnmodifiableArray<E> extends JSArray<E> {} // Already is JSIndexable.
/// An [Iterator] that iterates a JSArray.
///
class ArrayIterator<E> implements Iterator<E> {
final JSArray<E> _iterable;
@notNull
final int _length;
@notNull
int _index;
E _current;
ArrayIterator(JSArray<E> iterable)
: _iterable = iterable,
_length = iterable.length,
_index = 0;
E get current => _current;
bool moveNext() {
@notNull
int length = _iterable.length;
// We have to do the length check even on fixed length Arrays. If we can
// inline moveNext() we might be able to GVN the length and eliminate this
// check on known fixed length JSArray.
if (_length != length) {
throw throwConcurrentModificationError(_iterable);
}
if (_index >= length) {
_current = null;
return false;
}
_current = _iterable[_index];
_index++;
return true;
}
}

View file

@ -0,0 +1,826 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library dart._js_helper;
import 'dart:collection';
import 'dart:_foreign_helper' show JS, JS_STRING_CONCAT, JSExportName;
import 'dart:_interceptors';
import 'dart:_internal'
show
EfficientLengthIterable,
MappedIterable,
IterableElementError,
SubListIterable;
import 'dart:_native_typed_data';
import 'dart:_runtime' as dart;
part 'annotations.dart';
part 'linked_hash_map.dart';
part 'identity_hash_map.dart';
part 'custom_hash_map.dart';
part 'native_helper.dart';
part 'regexp_helper.dart';
part 'string_helper.dart';
part 'js_rti.dart';
class _Patch {
const _Patch();
}
const _Patch patch = _Patch();
/// Adapts a JS `[Symbol.iterator]` to a Dart `get iterator`.
///
/// This is the inverse of `JsIterator`, for classes where we can more
/// efficiently obtain a JS iterator instead of a Dart one.
///
// TODO(jmesserly): this adapter is to work around
// https://github.com/dart-lang/sdk/issues/28320
class DartIterator<E> implements Iterator<E> {
final _jsIterator;
E _current;
DartIterator(this._jsIterator);
E get current => _current;
bool moveNext() {
final ret = JS('', '#.next()', _jsIterator);
_current = JS('', '#.value', ret);
return JS<bool>('!', '!#.done', ret);
}
}
/// Used to compile `sync*`.
class SyncIterable<E> extends IterableBase<E> {
final Function() _initGenerator;
SyncIterable(this._initGenerator);
@JSExportName('Symbol.iterator')
_jsIterator() => _initGenerator();
get iterator => DartIterator(_initGenerator());
}
class Primitives {
@NoInline()
static int _parseIntError(String source, int handleError(String source)) {
if (handleError == null) throw FormatException(source);
return handleError(source);
}
static int parseInt(
@nullCheck String source, int _radix, int handleError(String source)) {
var re = JS('', r'/^\s*[+-]?((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$/i');
// TODO(jmesserly): this isn't reified List<String>, but it's safe to use as
// long as we use it locally and don't expose it to user code.
List<String> match = JS('', '#.exec(#)', re, source);
int digitsIndex = 1;
int hexIndex = 2;
int decimalIndex = 3;
if (match == null) {
// TODO(sra): It might be that the match failed due to unrecognized U+0085
// spaces. We could replace them with U+0020 spaces and try matching
// again.
return _parseIntError(source, handleError);
}
String decimalMatch = match[decimalIndex];
if (_radix == null) {
if (decimalMatch != null) {
// Cannot fail because we know that the digits are all decimal.
return JS<int>('!', r'parseInt(#, 10)', source);
}
if (match[hexIndex] != null) {
// Cannot fail because we know that the digits are all hex.
return JS<int>('!', r'parseInt(#, 16)', source);
}
return _parseIntError(source, handleError);
}
@notNull
var radix = _radix;
if (radix < 2 || radix > 36) {
throw RangeError.range(radix, 2, 36, 'radix');
}
if (radix == 10 && decimalMatch != null) {
// Cannot fail because we know that the digits are all decimal.
return JS<int>('!', r'parseInt(#, 10)', source);
}
// If radix >= 10 and we have only decimal digits the string is safe.
// Otherwise we need to check the digits.
if (radix < 10 || decimalMatch == null) {
// We know that the characters must be ASCII as otherwise the
// regexp wouldn't have matched. Lowercasing by doing `| 0x20` is thus
// guaranteed to be a safe operation, since it preserves digits
// and lower-cases ASCII letters.
int maxCharCode;
if (radix <= 10) {
// Allow all digits less than the radix. For example 0, 1, 2 for
// radix 3.
// "0".codeUnitAt(0) + radix - 1;
maxCharCode = (0x30 - 1) + radix;
} else {
// Letters are located after the digits in ASCII. Therefore we
// only check for the character code. The regexp above made already
// sure that the string does not contain anything but digits or
// letters.
// "a".codeUnitAt(0) + (radix - 10) - 1;
maxCharCode = (0x61 - 10 - 1) + radix;
}
assert(match[digitsIndex] is String);
String digitsPart = JS<String>('!', '#[#]', match, digitsIndex);
for (int i = 0; i < digitsPart.length; i++) {
int characterCode = digitsPart.codeUnitAt(i) | 0x20;
if (characterCode > maxCharCode) {
return _parseIntError(source, handleError);
}
}
}
// The above matching and checks ensures the source has at least one digits
// and all digits are suitable for the radix, so parseInt cannot return NaN.
return JS<int>('!', r'parseInt(#, #)', source, radix);
}
@NoInline()
static double _parseDoubleError(
String source, double handleError(String source)) {
if (handleError == null) {
throw FormatException('Invalid double', source);
}
return handleError(source);
}
static double parseDouble(
@nullCheck String source, double handleError(String source)) {
// Notice that JS parseFloat accepts garbage at the end of the string.
// Accept only:
// - [+/-]NaN
// - [+/-]Infinity
// - a Dart double literal
// We do allow leading or trailing whitespace.
if (!JS(
'bool',
r'/^\s*[+-]?(?:Infinity|NaN|'
r'(?:\.\d+|\d+(?:\.\d*)?)(?:[eE][+-]?\d+)?)\s*$/.test(#)',
source)) {
return _parseDoubleError(source, handleError);
}
num result = JS('!', r'parseFloat(#)', source);
if (result.isNaN) {
var trimmed = source.trim();
if (trimmed == 'NaN' || trimmed == '+NaN' || trimmed == '-NaN') {
return result;
}
return _parseDoubleError(source, handleError);
}
return result;
}
/** `r"$".codeUnitAt(0)` */
static const int DOLLAR_CHAR_VALUE = 36;
static int dateNow() => JS<int>('!', r'Date.now()');
static void initTicker() {
if (timerFrequency != null) return;
// Start with low-resolution. We overwrite the fields if we find better.
timerFrequency = 1000;
timerTicks = dateNow;
if (JS<bool>('!', 'typeof window == "undefined"')) return;
var jsWindow = JS('var', 'window');
if (jsWindow == null) return;
var performance = JS('var', '#.performance', jsWindow);
if (performance == null) return;
if (JS<bool>('!', 'typeof #.now != "function"', performance)) return;
timerFrequency = 1000000;
timerTicks = () => (1000 * JS<num>('!', '#.now()', performance)).floor();
}
static int timerFrequency;
static num Function() timerTicks;
static bool get isD8 {
return JS(
'bool',
'typeof version == "function"'
' && typeof os == "object" && "system" in os');
}
static bool get isJsshell {
return JS(
'bool', 'typeof version == "function" && typeof system == "function"');
}
static String currentUri() {
// In a browser return self.location.href.
if (JS<bool>('!', '!!#.location', dart.global_)) {
return JS<String>('!', '#.location.href', dart.global_);
}
// TODO(vsm): Consider supporting properly in non-browser settings.
return '';
}
// This is to avoid stack overflows due to very large argument arrays in
// apply(). It fixes http://dartbug.com/6919
@notNull
static String _fromCharCodeApply(List<int> array) {
const kMaxApply = 500;
@nullCheck
int end = array.length;
if (end <= kMaxApply) {
return JS<String>('!', r'String.fromCharCode.apply(null, #)', array);
}
String result = '';
for (int i = 0; i < end; i += kMaxApply) {
int chunkEnd = (i + kMaxApply < end) ? i + kMaxApply : end;
result = JS(
'String',
r'# + String.fromCharCode.apply(null, #.slice(#, #))',
result,
array,
i,
chunkEnd);
}
return result;
}
@notNull
static String stringFromCodePoints(JSArray<int> codePoints) {
List<int> a = <int>[];
for (@nullCheck var i in codePoints) {
if (i <= 0xffff) {
a.add(i);
} else if (i <= 0x10ffff) {
a.add(0xd800 + ((((i - 0x10000) >> 10) & 0x3ff)));
a.add(0xdc00 + (i & 0x3ff));
} else {
throw argumentErrorValue(i);
}
}
return _fromCharCodeApply(a);
}
@notNull
static String stringFromCharCodes(JSArray<int> charCodes) {
for (@nullCheck var i in charCodes) {
if (i < 0) throw argumentErrorValue(i);
if (i > 0xffff) return stringFromCodePoints(charCodes);
}
return _fromCharCodeApply(charCodes);
}
// [start] and [end] are validated.
@notNull
static String stringFromNativeUint8List(
NativeUint8List charCodes, @nullCheck int start, @nullCheck int end) {
const kMaxApply = 500;
if (end <= kMaxApply && start == 0 && end == charCodes.length) {
return JS<String>('!', r'String.fromCharCode.apply(null, #)', charCodes);
}
String result = '';
for (int i = start; i < end; i += kMaxApply) {
int chunkEnd = (i + kMaxApply < end) ? i + kMaxApply : end;
result = JS(
'String',
r'# + String.fromCharCode.apply(null, #.subarray(#, #))',
result,
charCodes,
i,
chunkEnd);
}
return result;
}
@notNull
static String stringFromCharCode(@nullCheck int charCode) {
if (0 <= charCode) {
if (charCode <= 0xffff) {
return JS<String>('!', 'String.fromCharCode(#)', charCode);
}
if (charCode <= 0x10ffff) {
var bits = charCode - 0x10000;
var low = 0xDC00 | (bits & 0x3ff);
var high = 0xD800 | (bits >> 10);
return JS<String>('!', 'String.fromCharCode(#, #)', high, low);
}
}
throw RangeError.range(charCode, 0, 0x10ffff);
}
static String stringConcatUnchecked(String string1, String string2) {
return JS_STRING_CONCAT(string1, string2);
}
static String flattenString(String str) {
return JS<String>('!', "#.charCodeAt(0) == 0 ? # : #", str, str, str);
}
static String getTimeZoneName(DateTime receiver) {
// Firefox and Chrome emit the timezone in parenthesis.
// Example: "Wed May 16 2012 21:13:00 GMT+0200 (CEST)".
// We extract this name using a regexp.
var d = lazyAsJsDate(receiver);
List match = JS('JSArray|Null', r'/\((.*)\)/.exec(#.toString())', d);
if (match != null) return match[1];
// Internet Explorer 10+ emits the zone name without parenthesis:
// Example: Thu Oct 31 14:07:44 PDT 2013
match = JS(
'JSArray|Null',
// Thu followed by a space.
r'/^[A-Z,a-z]{3}\s'
// Oct 31 followed by space.
r'[A-Z,a-z]{3}\s\d+\s'
// Time followed by a space.
r'\d{2}:\d{2}:\d{2}\s'
// The time zone name followed by a space.
r'([A-Z]{3,5})\s'
// The year.
r'\d{4}$/'
'.exec(#.toString())',
d);
if (match != null) return match[1];
// IE 9 and Opera don't provide the zone name. We fall back to emitting the
// UTC/GMT offset.
// Example (IE9): Wed Nov 20 09:51:00 UTC+0100 2013
// (Opera): Wed Nov 20 2013 11:03:38 GMT+0100
match = JS('JSArray|Null', r'/(?:GMT|UTC)[+-]\d{4}/.exec(#.toString())', d);
if (match != null) return match[0];
return "";
}
static int getTimeZoneOffsetInMinutes(DateTime receiver) {
// Note that JS and Dart disagree on the sign of the offset.
return -JS<int>('!', r'#.getTimezoneOffset()', lazyAsJsDate(receiver));
}
static num valueFromDecomposedDate(
@nullCheck int years,
@nullCheck int month,
@nullCheck int day,
@nullCheck int hours,
@nullCheck int minutes,
@nullCheck int seconds,
@nullCheck int milliseconds,
@nullCheck bool isUtc) {
final int MAX_MILLISECONDS_SINCE_EPOCH = 8640000000000000;
var jsMonth = month - 1;
num value;
if (isUtc) {
value = JS('!', r'Date.UTC(#, #, #, #, #, #, #)', years, jsMonth, day,
hours, minutes, seconds, milliseconds);
} else {
value = JS('!', r'new Date(#, #, #, #, #, #, #).valueOf()', years,
jsMonth, day, hours, minutes, seconds, milliseconds);
}
if (value.isNaN ||
value < -MAX_MILLISECONDS_SINCE_EPOCH ||
value > MAX_MILLISECONDS_SINCE_EPOCH) {
return null;
}
if (years <= 0 || years < 100) return patchUpY2K(value, years, isUtc);
return value;
}
static num patchUpY2K(value, years, isUtc) {
var date = JS('', r'new Date(#)', value);
if (isUtc) {
JS('', r'#.setUTCFullYear(#)', date, years);
} else {
JS('', r'#.setFullYear(#)', date, years);
}
return JS('!', r'#.valueOf()', date);
}
// Lazily keep a JS Date stored in the JS object.
static lazyAsJsDate(DateTime receiver) {
if (JS<bool>('!', r'#.date === (void 0)', receiver)) {
JS('void', r'#.date = new Date(#)', receiver,
receiver.millisecondsSinceEpoch);
}
return JS('var', r'#.date', receiver);
}
// The getters for date and time parts below add a positive integer to ensure
// that the result is really an integer, because the JavaScript implementation
// may return -0.0 instead of 0.
static int getYear(DateTime receiver) {
return (receiver.isUtc)
? JS<int>('!', r'(#.getUTCFullYear() + 0)', lazyAsJsDate(receiver))
: JS<int>('!', r'(#.getFullYear() + 0)', lazyAsJsDate(receiver));
}
static int getMonth(DateTime receiver) {
return (receiver.isUtc)
? JS<int>('!', r'#.getUTCMonth() + 1', lazyAsJsDate(receiver))
: JS<int>('!', r'#.getMonth() + 1', lazyAsJsDate(receiver));
}
static int getDay(DateTime receiver) {
return (receiver.isUtc)
? JS<int>('!', r'(#.getUTCDate() + 0)', lazyAsJsDate(receiver))
: JS<int>('!', r'(#.getDate() + 0)', lazyAsJsDate(receiver));
}
static int getHours(DateTime receiver) {
return (receiver.isUtc)
? JS<int>('!', r'(#.getUTCHours() + 0)', lazyAsJsDate(receiver))
: JS<int>('!', r'(#.getHours() + 0)', lazyAsJsDate(receiver));
}
static int getMinutes(DateTime receiver) {
return (receiver.isUtc)
? JS<int>('!', r'(#.getUTCMinutes() + 0)', lazyAsJsDate(receiver))
: JS<int>('!', r'(#.getMinutes() + 0)', lazyAsJsDate(receiver));
}
static int getSeconds(DateTime receiver) {
return (receiver.isUtc)
? JS<int>('!', r'(#.getUTCSeconds() + 0)', lazyAsJsDate(receiver))
: JS<int>('!', r'(#.getSeconds() + 0)', lazyAsJsDate(receiver));
}
static int getMilliseconds(DateTime receiver) {
return (receiver.isUtc)
? JS<int>('!', r'(#.getUTCMilliseconds() + 0)', lazyAsJsDate(receiver))
: JS<int>('!', r'(#.getMilliseconds() + 0)', lazyAsJsDate(receiver));
}
static int getWeekday(DateTime receiver) {
int weekday = (receiver.isUtc)
? JS<int>('!', r'#.getUTCDay() + 0', lazyAsJsDate(receiver))
: JS<int>('!', r'#.getDay() + 0', lazyAsJsDate(receiver));
// Adjust by one because JS weeks start on Sunday.
return (weekday + 6) % 7 + 1;
}
static num valueFromDateString(str) {
if (str is! String) throw argumentErrorValue(str);
num value = JS('!', r'Date.parse(#)', str);
if (value.isNaN) throw argumentErrorValue(str);
return value;
}
static getProperty(object, key) {
if (object == null || object is bool || object is num || object is String) {
throw argumentErrorValue(object);
}
return JS('var', '#[#]', object, key);
}
static void setProperty(object, key, value) {
if (object == null || object is bool || object is num || object is String) {
throw argumentErrorValue(object);
}
JS('void', '#[#] = #', object, key, value);
}
}
/**
* Diagnoses an indexing error. Returns the ArgumentError or RangeError that
* describes the problem.
*/
@NoInline()
Error diagnoseIndexError(indexable, int index) {
int length = indexable.length;
// The following returns the same error that would be thrown by calling
// [RangeError.checkValidIndex] with no optional parameters provided.
if (index < 0 || index >= length) {
return RangeError.index(index, indexable, 'index', null, length);
}
// The above should always match, but if it does not, use the following.
return RangeError.value(index, 'index');
}
/**
* Diagnoses a range error. Returns the ArgumentError or RangeError that
* describes the problem.
*/
@NoInline()
Error diagnoseRangeError(int start, int end, int length) {
if (start == null) {
return ArgumentError.value(start, 'start');
}
if (start < 0 || start > length) {
return RangeError.range(start, 0, length, 'start');
}
if (end != null) {
if (end < start || end > length) {
return RangeError.range(end, start, length, 'end');
}
}
// The above should always match, but if it does not, use the following.
return ArgumentError.value(end, "end");
}
@notNull
int stringLastIndexOfUnchecked(receiver, element, start) =>
JS<int>('!', r'#.lastIndexOf(#, #)', receiver, element, start);
/// 'factory' for constructing ArgumentError.value to keep the call sites small.
@NoInline()
ArgumentError argumentErrorValue(object) {
return ArgumentError.value(object);
}
void throwArgumentErrorValue(value) {
throw argumentErrorValue(value);
}
checkInt(value) {
if (value is! int) throw argumentErrorValue(value);
return value;
}
throwRuntimeError(message) {
throw RuntimeError(message);
}
throwAbstractClassInstantiationError(className) {
throw AbstractClassInstantiationError(className);
}
@NoInline()
throwConcurrentModificationError(collection) {
throw ConcurrentModificationError(collection);
}
class JsNoSuchMethodError extends Error implements NoSuchMethodError {
final String _message;
final String _method;
final String _receiver;
JsNoSuchMethodError(this._message, match)
: _method = match == null ? null : JS('String|Null', '#.method', match),
_receiver =
match == null ? null : JS('String|Null', '#.receiver', match);
String toString() {
if (_method == null) return 'NoSuchMethodError: $_message';
if (_receiver == null) {
return "NoSuchMethodError: method not found: '$_method' ($_message)";
}
return "NoSuchMethodError: "
"method not found: '$_method' on '$_receiver' ($_message)";
}
}
class UnknownJsTypeError extends Error {
final String _message;
UnknownJsTypeError(this._message);
String toString() => _message.isEmpty ? 'Error' : 'Error: $_message';
}
/**
* Called by generated code to build a map literal. [keyValuePairs] is
* a list of key, value, key, value, ..., etc.
*/
fillLiteralMap(keyValuePairs, Map result) {
// TODO(johnniwinther): Use JSArray to optimize this code instead of calling
// [getLength] and [getIndex].
int index = 0;
int length = getLength(keyValuePairs);
while (index < length) {
var key = getIndex(keyValuePairs, index++);
var value = getIndex(keyValuePairs, index++);
result[key] = value;
}
return result;
}
bool jsHasOwnProperty(var jsObject, String property) {
return JS<bool>('!', r'#.hasOwnProperty(#)', jsObject, property);
}
jsPropertyAccess(var jsObject, String property) {
return JS('var', r'#[#]', jsObject, property);
}
/**
* Called at the end of unaborted switch cases to get the singleton
* FallThroughError exception that will be thrown.
*/
getFallThroughError() => FallThroughErrorImplementation();
/**
* A metadata annotation describing the types instantiated by a native element.
*
* The annotation is valid on a native method and a field of a native class.
*
* By default, a field of a native class is seen as an instantiation point for
* all native classes that are a subtype of the field's type, and a native
* method is seen as an instantiation point fo all native classes that are a
* subtype of the method's return type, or the argument types of the declared
* type of the method's callback parameter.
*
* An @[Creates] annotation overrides the default set of instantiated types. If
* one or more @[Creates] annotations are present, the type of the native
* element is ignored, and the union of @[Creates] annotations is used instead.
* The names in the strings are resolved and the program will fail to compile
* with dart2js if they do not name types.
*
* The argument to [Creates] is a string. The string is parsed as the names of
* one or more types, separated by vertical bars `|`. There are some special
* names:
*
* * `=Object`. This means 'exactly Object', which is a plain JavaScript object
* with properties and none of the subtypes of Object.
*
* Example: we may know that a method always returns a specific implementation:
*
* @Creates('_NodeList')
* List<Node> getElementsByTagName(String tag) native;
*
* Useful trick: A method can be marked as not instantiating any native classes
* with the annotation `@Creates('Null')`. This is useful for fields on native
* classes that are used only in Dart code.
*
* @Creates('Null')
* var _cachedFoo;
*/
class Creates {
final String types;
const Creates(this.types);
}
/**
* A metadata annotation describing the types returned or yielded by a native
* element.
*
* The annotation is valid on a native method and a field of a native class.
*
* By default, a native method or field is seen as returning or yielding all
* subtypes if the method return type or field type. This annotation allows a
* more precise set of types to be specified.
*
* See [Creates] for the syntax of the argument.
*
* Example: IndexedDB keys are numbers, strings and JavaScript Arrays of keys.
*
* @Returns('String|num|JSExtendableArray')
* dynamic key;
*
* // Equivalent:
* @Returns('String') @Returns('num') @Returns('JSExtendableArray')
* dynamic key;
*/
class Returns {
final String types;
const Returns(this.types);
}
/**
* A metadata annotation placed on native methods and fields of native classes
* to specify the JavaScript name.
*
* This example declares a Dart field + getter + setter called `$dom_title` that
* corresponds to the JavaScript property `title`.
*
* class Document native "*Foo" {
* @JSName('title')
* String $dom_title;
* }
*/
class JSName {
final String name;
const JSName(this.name);
}
/**
* Special interface recognized by the compiler and implemented by DOM
* objects that support integer indexing. This interface is not
* visible to anyone, and is only injected into special libraries.
*/
abstract class JavaScriptIndexingBehavior<E> {}
// TODO(lrn): These exceptions should be implemented in core.
// When they are, remove the 'Implementation' here.
/// Thrown by type assertions that fail.
class TypeErrorImpl extends Error implements TypeError {
final String message;
TypeErrorImpl(this.message);
String toString() => message;
}
/// Thrown by the 'as' operator if the cast isn't valid.
class CastErrorImpl extends Error implements CastError {
final String message;
CastErrorImpl(this.message);
String toString() => message;
}
class FallThroughErrorImplementation extends FallThroughError {
String toString() => "Switch case fall-through.";
}
/**
* Error thrown when a runtime error occurs.
*/
class RuntimeError extends Error {
final message;
RuntimeError(this.message);
String toString() => "RuntimeError: $message";
}
/// Error thrown by DDC when an `assert()` fails (with or without a message).
class AssertionErrorImpl extends AssertionError {
final String _fileUri;
final int _line;
final int _column;
final String _conditionSource;
AssertionErrorImpl(Object message,
[this._fileUri, this._line, this._column, this._conditionSource])
: super(message);
String toString() {
var failureMessage = "";
if (_fileUri != null &&
_line != null &&
_column != null &&
_conditionSource != null) {
failureMessage += "$_fileUri:${_line}:${_column}\n$_conditionSource\n";
}
failureMessage +=
message != null ? Error.safeToString(message) : "is not true";
return "Assertion failed: $failureMessage";
}
}
/**
* Creates a random number with 64 bits of randomness.
*
* This will be truncated to the 53 bits available in a double.
*/
int random64() {
// TODO(lrn): Use a secure random source.
int int32a = JS("int", "(Math.random() * 0x100000000) >>> 0");
int int32b = JS("int", "(Math.random() * 0x100000000) >>> 0");
return int32a + int32b * 0x100000000;
}
class BooleanConversionAssertionError extends AssertionError {
toString() => 'Failed assertion: boolean expression must not be null';
}
// Hook to register new global object. This is invoked from dart:html
// whenever a new window is accessed for the first time.
void registerGlobalObject(object) {
try {
if (dart.polyfill(object)) {
dart.applyAllExtensions(object);
}
} catch (e) {
// This may fail due to cross-origin errors. In that case, we shouldn't
// need to polyfill as we can't get objects from that frame.
// TODO(vsm): Detect this more robustly - ideally before we try to polyfill.
}
}
/// Expose browser JS classes.
void applyExtension(name, nativeObject) {
dart.applyExtension(name, nativeObject);
}
/// Used internally by DDC to map ES6 symbols to Dart.
class PrivateSymbol implements Symbol {
// TODO(jmesserly): could also get this off the native symbol instead of
// storing it. Mirrors already does this conversion.
final String _name;
final Object _nativeSymbol;
const PrivateSymbol(this._name, this._nativeSymbol);
static String getName(Symbol symbol) => (symbol as PrivateSymbol)._name;
static Object getNativeSymbol(Symbol symbol) {
if (symbol is PrivateSymbol) return symbol._nativeSymbol;
return null;
}
bool operator ==(other) =>
other is PrivateSymbol &&
_name == other._name &&
identical(_nativeSymbol, other._nativeSymbol);
get hashCode => _name.hashCode;
// TODO(jmesserly): is this equivalent to _nativeSymbol toString?
toString() => 'Symbol("$_name")';
}

View file

@ -0,0 +1,598 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library dart._js_mirrors;
import 'dart:mirrors';
import 'dart:_runtime' as dart;
import 'dart:_foreign_helper' show JS;
import 'dart:_internal' as _internal show Symbol;
import 'dart:_js_helper' show PrivateSymbol;
String getName(Symbol symbol) {
if (symbol is PrivateSymbol) {
return PrivateSymbol.getName(symbol);
} else {
return _internal.Symbol.getName(symbol as _internal.Symbol);
}
}
Symbol getSymbol(name, library) =>
throw UnimplementedError("MirrorSystem.getSymbol unimplemented");
final currentJsMirrorSystem = JsMirrorSystem();
final _typeMirror = JS('', 'Symbol("_typeMirror")');
InstanceMirror reflect(reflectee) {
// TODO(vsm): Consider caching the mirror here. Unlike the type below,
// reflectee may be a primitive - i.e., we can't just add an expando.
if (reflectee is Function) {
return JsClosureMirror._(reflectee);
} else {
return JsInstanceMirror._(reflectee);
}
}
TypeMirror reflectType(Type key) {
var unwrapped = dart.unwrapType(key);
var property =
JS('', 'Object.getOwnPropertyDescriptor(#, #)', unwrapped, _typeMirror);
if (property != null) {
return JS('', '#.value', property);
}
// TODO(vsm): Might not be a class.
var mirror = JsClassMirror._(key);
JS('', '#[#] = #', unwrapped, _typeMirror, mirror);
return mirror;
}
typedef T _Lazy<T>();
dynamic _getESSymbol(Symbol symbol) => PrivateSymbol.getNativeSymbol(symbol);
dynamic _getMember(Symbol symbol) {
var privateSymbol = _getESSymbol(symbol);
if (privateSymbol != null) {
return privateSymbol;
}
var name = getName(symbol);
// TODO(jacobr): this code is duplicated in code_generator.dart
switch (name) {
case '[]':
name = '_get';
break;
case '[]=':
name = '_set';
break;
case 'unary-':
name = '_negate';
break;
case 'constructor':
case 'prototype':
name = '_$name';
break;
}
return name;
}
String _getNameForESSymbol(member) {
// Convert private JS symbol "Symbol(_foo)" to string "_foo".
assert(JS<bool>('!', 'typeof # == "symbol"', member));
var str = member.toString();
assert(str.startsWith('Symbol(') && str.endsWith(')'));
return str.substring(7, str.length - 1);
}
Symbol _getSymbolForESSymbol(member) {
var name = _getNameForESSymbol(member);
return PrivateSymbol(name, member);
}
// The [member] must be either a string (public) or an ES6 symbol (private).
Symbol _getSymbolForMember(member) {
if (member is String) {
return Symbol(member);
} else {
var name = _getNameForESSymbol(member);
return PrivateSymbol(name, member);
}
}
Map<Symbol, dynamic> _toDartMap(data) {
if (data == null) return {};
var map = Map<Symbol, dynamic>();
// Note: we recorded a map from fields/methods to their type and metadata.
// The key is a string name for public members but an ES6 symbol for private
// ones. That's works nicely for dynamic operations, but dart:mirrors expects
// Dart symbols, so we convert here.
var publicMembers = JS('', 'Object.getOwnPropertyNames(#)', data);
for (var member in publicMembers) {
var symbol = Symbol(member);
map[symbol] = JS('', '#[#]', data, member);
}
var privateMembers = JS('', 'Object.getOwnPropertySymbols(#)', data);
for (var member in privateMembers) {
var symbol = _getSymbolForESSymbol(member);
map[symbol] = JS('', '#[#]', data, member);
}
return map;
}
dynamic _runtimeType(obj) => dart.wrapType(dart.getReifiedType(obj));
_unimplemented(Type t, Invocation i) {
throw UnimplementedError('$t.${getName(i.memberName)} unimplemented');
}
dynamic _toJsMap(Map<Symbol, dynamic> map) {
if (map == null) return null;
var obj = JS('', '{}');
map.forEach((Symbol key, value) {
JS('', '#[#] = #', obj, getName(key), value);
});
return obj;
}
class JsMirrorSystem implements MirrorSystem {
get libraries => const {};
noSuchMethod(Invocation i) {
_unimplemented(this.runtimeType, i);
}
}
class JsMirror implements Mirror {
noSuchMethod(Invocation i) {
_unimplemented(this.runtimeType, i);
}
}
class JsCombinatorMirror extends JsMirror implements CombinatorMirror {}
class JsDeclarationMirror extends JsMirror implements DeclarationMirror {}
class JsIsolateMirror extends JsMirror implements IsolateMirror {}
class JsLibraryDependencyMirror extends JsMirror
implements LibraryDependencyMirror {}
class JsObjectMirror extends JsMirror implements ObjectMirror {}
class JsInstanceMirror extends JsObjectMirror implements InstanceMirror {
// Reflected object
final reflectee;
bool get hasReflectee => true;
ClassMirror get type {
// The spec guarantees that `null` is the singleton instance of the `Null`
// class.
if (reflectee == null) return reflectClass(Null);
return reflectType(_runtimeType(reflectee));
}
JsInstanceMirror._(this.reflectee);
bool operator ==(Object other) {
return (other is JsInstanceMirror) && identical(reflectee, other.reflectee);
}
int get hashCode {
// Avoid hash collisions with the reflectee. This constant is in Smi range
// and happens to be the inner padding from RFC 2104.
return identityHashCode(reflectee) ^ 0x36363636;
}
InstanceMirror getField(Symbol symbol) {
var name = _getMember(symbol);
var field = dart.dloadMirror(reflectee, name);
return reflect(field);
}
InstanceMirror setField(Symbol symbol, Object value) {
var name = _getMember(symbol);
dart.dputMirror(reflectee, name, value);
return reflect(value);
}
InstanceMirror invoke(Symbol symbol, List<dynamic> args,
[Map<Symbol, dynamic> namedArgs]) {
var name = _getMember(symbol);
var result =
dart.callMethod(reflectee, name, null, args, _toJsMap(namedArgs), name);
return reflect(result);
}
String toString() => "InstanceMirror on '$reflectee'";
}
class JsClosureMirror extends JsInstanceMirror implements ClosureMirror {
JsClosureMirror._(reflectee) : super._(reflectee);
InstanceMirror apply(List<dynamic> args, [Map<Symbol, dynamic> namedArgs]) {
var result = dart.dcall(reflectee, args, _toJsMap(namedArgs));
return reflect(result);
}
}
// For generic classes, mirrors uses the same representation, [ClassMirror],
// for the instantiated and uninstantiated type. Somewhat awkwardly, most APIs
// (e.g., [newInstance]) treat the uninstantiated type as if instantiated
// with all dynamic. The representation below is correspondingly a bit wonky.
// For an uninstantiated generic class, [_cls] is the instantiated type (with
// dynamic) and [_raw] is null. For an instantiated generic class, [_cls] is
// the instantiated type (with the corresponding type parameters), and [_raw]
// is the generic factory.
class JsClassMirror extends JsMirror implements ClassMirror {
final Type _cls;
final Symbol simpleName;
// Generic class factory for instantiated types.
final dynamic _raw;
ClassMirror _originalDeclaration;
// TODO(vsm): Do this properly
ClassMirror _mixin = null;
List<TypeMirror> _typeArguments;
List<InstanceMirror> _metadata;
Map<Symbol, DeclarationMirror> _declarations;
List<InstanceMirror> get metadata {
if (_metadata == null) {
// Load metadata.
var unwrapped = dart.unwrapType(_cls);
// Only get metadata directly embedded on this class, not its
// superclasses.
Function fn = JS(
'',
'Object.hasOwnProperty.call(#, dart.metadata) ? #[dart.metadata] : null',
unwrapped,
unwrapped);
_metadata = (fn == null)
? const <InstanceMirror>[]
: List<InstanceMirror>.unmodifiable(fn().map((i) => reflect(i)));
}
return _metadata;
}
Map<Symbol, DeclarationMirror> get declarations {
if (_declarations == null) {
// Load declarations.
// TODO(vsm): This is only populating the default constructor right now.
_declarations = Map<Symbol, DeclarationMirror>();
var unwrapped = dart.unwrapType(_cls);
var constructors = _toDartMap(dart.getConstructors(unwrapped));
constructors.forEach((symbol, ft) {
var name = getName(symbol);
_declarations[symbol] = JsMethodMirror._constructor(this, symbol, ft);
});
if (constructors.isEmpty) {
// Add a default
var name = 'new';
var ft = dart.fnType(dart.unwrapType(_cls), []);
var symbol = Symbol(name);
_declarations[symbol] = JsMethodMirror._constructor(this, symbol, ft);
}
var fields = _toDartMap(dart.getFields(unwrapped));
fields.forEach((symbol, t) {
_declarations[symbol] = JsVariableMirror._fromField(symbol, t);
});
var methods = _toDartMap(dart.getMethods(unwrapped));
methods.forEach((symbol, ft) {
var name = getName(symbol);
_declarations[symbol] =
JsMethodMirror._instanceMethod(this, symbol, ft);
});
getterType(type) {
if (JS<bool>('!', '# instanceof Array', type)) {
var array = JS('', '#.slice()', type);
type = JS('', '#[0]', array);
JS('', '#[0] = #', array, dart.fnType(type, []));
return array;
} else {
return dart.fnType(type, []);
}
}
var getters = _toDartMap(dart.getGetters(unwrapped));
getters.forEach((symbol, type) {
_declarations[symbol] =
JsMethodMirror._instanceMethod(this, symbol, getterType(type));
});
setterType(type) {
if (JS<bool>('!', '# instanceof Array', type)) {
var array = JS('', '#.slice()', type);
type = JS('', '#[0]', array);
JS('', '#[0] = #', array, dart.fnType(dart.void_, [type]));
return array;
} else {
return dart.fnType(dart.void_, [type]);
}
}
var setters = _toDartMap(dart.getSetters(unwrapped));
setters.forEach((symbol, type) {
var name = getName(symbol) + '=';
// Create a separate symbol for the setter.
symbol = PrivateSymbol(name, _getESSymbol(symbol));
_declarations[symbol] =
JsMethodMirror._instanceMethod(this, symbol, setterType(type));
});
var staticFields = _toDartMap(dart.getStaticFields(unwrapped));
staticFields.forEach((symbol, t) {
_declarations[symbol] = JsVariableMirror._fromField(symbol, t);
});
var statics = _toDartMap(dart.getStaticMethods(unwrapped));
statics.forEach((symbol, ft) {
_declarations[symbol] = JsMethodMirror._staticMethod(this, symbol, ft);
});
var staticGetters = _toDartMap(dart.getStaticGetters(unwrapped));
staticGetters.forEach((symbol, type) {
_declarations[symbol] =
JsMethodMirror._staticMethod(this, symbol, getterType(type));
});
var staticSetters = _toDartMap(dart.getStaticSetters(unwrapped));
staticSetters.forEach((symbol, type) {
_declarations[symbol] =
JsMethodMirror._staticMethod(this, symbol, setterType(type));
});
_declarations =
Map<Symbol, DeclarationMirror>.unmodifiable(_declarations);
}
return _declarations;
}
JsClassMirror._(Type cls, {bool instantiated = true})
: _cls = cls,
_raw = instantiated ? dart.getGenericClass(dart.unwrapType(cls)) : null,
simpleName = Symbol(JS<String>('!', '#.name', dart.unwrapType(cls))) {
var typeArgs = dart.getGenericArgs(dart.unwrapType(_cls));
if (typeArgs == null) {
_typeArguments = const [];
} else {
_typeArguments =
List.unmodifiable(typeArgs.map((t) => reflectType(dart.wrapType(t))));
}
}
InstanceMirror newInstance(Symbol constructorName, List args,
[Map<Symbol, dynamic> namedArgs]) {
// TODO(vsm): Support named arguments.
var name = getName(constructorName);
assert(namedArgs == null || namedArgs.isEmpty);
// Default constructors are mapped to new.
if (name == '') name = 'new';
var cls = dart.unwrapType(_cls);
var ctr = JS('', '#.#', cls, name);
// Only generative Dart constructors are wired up as real JS constructors.
var instance = JS<bool>('!', '#.prototype == #.prototype', cls, ctr)
// Generative
? JS('', 'new #(...#)', ctr, args)
// Factory
: JS('', '#(...#)', ctr, args);
return reflect(instance);
}
// TODO(vsm): Need to check for NSM, types on accessors below. Unlike the
// InstanceMirror case, there is no dynamic helper to delegate to - we never
// need a dload, etc. on a static.
InstanceMirror getField(Symbol symbol) {
var name = getName(symbol);
return reflect(JS('', '#[#]', dart.unwrapType(_cls), name));
}
InstanceMirror setField(Symbol symbol, Object value) {
var name = getName(symbol);
JS('', '#[#] = #', dart.unwrapType(_cls), name, value);
return reflect(value);
}
InstanceMirror invoke(Symbol symbol, List<dynamic> args,
[Map<Symbol, dynamic> namedArgs]) {
var name = getName(symbol);
if (namedArgs != null) {
args = List.from(args);
args.add(_toJsMap(namedArgs));
}
var result = JS('', '#.#(...#)', dart.unwrapType(_cls), name, args);
return reflect(result);
}
List<ClassMirror> get superinterfaces {
_Lazy<List<Type>> interfaceThunk =
JS('', '#[dart.implements]', dart.unwrapType(_cls));
if (interfaceThunk == null) {
return [];
} else {
List<Type> interfaces = interfaceThunk();
return interfaces.map((t) => reflectType(t)).toList();
}
}
bool get hasReflectedType => true;
Type get reflectedType {
return _cls;
}
bool get isOriginalDeclaration => _raw == null;
List<TypeMirror> get typeArguments => _typeArguments;
TypeMirror get originalDeclaration {
if (_raw == null) {
return this;
}
if (_originalDeclaration != null) {
return _originalDeclaration;
}
_originalDeclaration = JsClassMirror._(dart.wrapType(JS('', '#()', _raw)),
instantiated: false);
return _originalDeclaration;
}
ClassMirror get superclass {
if (_cls == Object) {
return null;
} else {
return reflectType(
dart.wrapType(JS<Type>('!', '#.__proto__', dart.unwrapType(_cls))));
}
}
ClassMirror get mixin {
if (_mixin != null) {
return _mixin;
}
var mixin = dart.getMixin(dart.unwrapType(_cls));
if (mixin == null) {
// If there is no mixin, return this mirror per API.
_mixin = this;
return _mixin;
}
_mixin = reflectType(dart.wrapType(mixin));
return _mixin;
}
String toString() => "ClassMirror on '$_cls'";
}
class JsVariableMirror extends JsMirror implements VariableMirror {
final Symbol _symbol;
final String _name;
final TypeMirror type;
final List<InstanceMirror> metadata;
final bool isFinal;
// TODO(vsm): Refactor this out.
Symbol get simpleName => _symbol;
// TODO(vsm): Fix this
final bool isStatic = false;
JsVariableMirror._(Symbol symbol, Type t, List annotations,
{this.isFinal = false})
: _symbol = symbol,
_name = getName(symbol),
type = reflectType(t),
metadata =
List<InstanceMirror>.unmodifiable(annotations?.map(reflect) ?? []);
JsVariableMirror._fromField(Symbol symbol, fieldInfo)
: this._(symbol, dart.wrapType(JS('', '#.type', fieldInfo)),
JS('', '#.metadata', fieldInfo),
isFinal: JS<bool>('!', '#.isFinal', fieldInfo));
String toString() => "VariableMirror on '$_name'";
}
class JsParameterMirror extends JsVariableMirror implements ParameterMirror {
JsParameterMirror._(Symbol member, Type t, List annotations)
: super._(member, t, annotations);
String toString() => "ParameterMirror on '$_name'";
}
class JsMethodMirror extends JsMirror implements MethodMirror {
final Symbol _symbol;
final String _name;
List<ParameterMirror> _params;
List<InstanceMirror> _metadata;
final bool isConstructor;
final bool isStatic;
// TODO(vsm): Fix this
final bool isFinal = false;
bool get isSetter => _name.endsWith('=');
bool get isPrivate => _name.startsWith('_');
// TODO(vsm): Refactor this out.
Symbol get simpleName => _symbol;
JsMethodMirror._constructor(JsClassMirror cls, Symbol symbol, ftype)
: _symbol = symbol,
_name = getName(symbol),
isConstructor = true,
isStatic = false {
_createParameterMirrorList(ftype);
}
JsMethodMirror._instanceMethod(JsClassMirror cls, Symbol symbol, ftype)
: _symbol = symbol,
_name = getName(symbol),
isConstructor = false,
isStatic = false {
_createParameterMirrorList(ftype);
}
JsMethodMirror._staticMethod(JsClassMirror cls, Symbol symbol, ftype)
: _symbol = symbol,
_name = getName(symbol),
isConstructor = false,
isStatic = true {
_createParameterMirrorList(ftype);
}
// TODO(vsm): Support named constructors.
Symbol get constructorName => isConstructor ? _symbol : null;
List<ParameterMirror> get parameters => _params;
List<InstanceMirror> get metadata => _metadata;
void _createParameterMirrorList(ftype) {
if (ftype == null) {
// TODO(vsm): No explicit constructor. Verify this.
_params = const [];
_metadata = const [];
return;
}
// TODO(vsm): Why does generic function type trigger true for List?
if (ftype is! Function && ftype is List) {
// Record metadata
_metadata = List<InstanceMirror>.unmodifiable(
ftype.skip(1).map((a) => reflect(a)));
ftype = ftype[0];
} else {
_metadata = const [];
}
// TODO(vsm): Handle generic function types properly. Or deprecate mirrors
// before we need to!
ftype = dart.getFunctionTypeMirror(ftype);
// TODO(vsm): Add named args.
List args = ftype.args;
List opts = ftype.optionals;
var params = List<ParameterMirror>(args.length + opts.length);
for (var i = 0; i < args.length; ++i) {
var type = args[i];
var metadata = ftype.metadata[i];
// TODO(vsm): Recover the param name.
var param =
JsParameterMirror._(Symbol(''), dart.wrapType(type), metadata);
params[i] = param;
}
for (var i = 0; i < opts.length; ++i) {
var type = opts[i];
var metadata = ftype.metadata[args.length + i];
// TODO(vsm): Recover the param name.
var param =
JsParameterMirror._(Symbol(''), dart.wrapType(type), metadata);
params[i + args.length] = param;
}
_params = List.unmodifiable(params);
}
String toString() => "MethodMirror on '$_name'";
}

View file

@ -0,0 +1,627 @@
// 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.
part of dart._interceptors;
/**
* The implementation of Dart's int & double methods.
* These are made available as extension methods on `Number` in JS.
*/
@JsPeerInterface(name: 'Number')
class JSNumber extends Interceptor implements int, double {
const JSNumber();
@notNull
int compareTo(@nullCheck num b) {
if (this < b) {
return -1;
} else if (this > b) {
return 1;
} else if (this == b) {
if (this == 0) {
bool bIsNegative = b.isNegative;
if (isNegative == bIsNegative) return 0;
if (isNegative) return -1;
return 1;
}
return 0;
} else if (isNaN) {
if (b.isNaN) {
return 0;
}
return 1;
} else {
return -1;
}
}
@notNull
bool get isNegative => (this == 0) ? (1 / this) < 0 : this < 0;
@notNull
bool get isNaN => JS<bool>('!', r'isNaN(#)', this);
@notNull
bool get isInfinite {
return JS<bool>('!', r'# == (1/0)', this) ||
JS<bool>('!', r'# == (-1/0)', this);
}
@notNull
bool get isFinite => JS<bool>('!', r'isFinite(#)', this);
@notNull
JSNumber remainder(@nullCheck num b) {
return JS<num>('!', r'# % #', this, b);
}
@notNull
JSNumber abs() => JS<num>('!', r'Math.abs(#)', this);
@notNull
JSNumber get sign => this > 0 ? 1 : this < 0 ? -1 : this;
@notNull
static const int _MIN_INT32 = -0x80000000;
@notNull
static const int _MAX_INT32 = 0x7FFFFFFF;
@notNull
int toInt() {
if (this >= _MIN_INT32 && this <= _MAX_INT32) {
return JS<int>('!', '# | 0', this);
}
if (JS<bool>('!', r'isFinite(#)', this)) {
return JS<int>(
'!', r'# + 0', truncateToDouble()); // Converts -0.0 to +0.0.
}
// This is either NaN, Infinity or -Infinity.
throw UnsupportedError(JS("String", '"" + #', this));
}
@notNull
int truncate() => toInt();
@notNull
int ceil() => ceilToDouble().toInt();
@notNull
int floor() => floorToDouble().toInt();
@notNull
int round() {
if (this > 0) {
// This path excludes the special cases -0.0, NaN and -Infinity, leaving
// only +Infinity, for which a direct test is faster than [isFinite].
if (JS<bool>('!', r'# !== (1/0)', this)) {
return JS<int>('!', r'Math.round(#)', this);
}
} else if (JS<bool>('!', '# > (-1/0)', this)) {
// This test excludes NaN and -Infinity, leaving only -0.0.
//
// Subtraction from zero rather than negation forces -0.0 to 0.0 so code
// inside Math.round and code to handle result never sees -0.0, which on
// some JavaScript VMs can be a slow path.
return JS<int>('!', r'0 - Math.round(0 - #)', this);
}
// This is either NaN, Infinity or -Infinity.
throw UnsupportedError(JS("String", '"" + #', this));
}
@notNull
double ceilToDouble() => JS<num>('!', r'Math.ceil(#)', this);
@notNull
double floorToDouble() => JS<num>('!', r'Math.floor(#)', this);
@notNull
double roundToDouble() {
if (this < 0) {
return JS<num>('!', r'-Math.round(-#)', this);
} else {
return JS<num>('!', r'Math.round(#)', this);
}
}
@notNull
double truncateToDouble() => this < 0 ? ceilToDouble() : floorToDouble();
@notNull
num clamp(@nullCheck num lowerLimit, @nullCheck num upperLimit) {
if (lowerLimit.compareTo(upperLimit) > 0) {
throw argumentErrorValue(lowerLimit);
}
if (this.compareTo(lowerLimit) < 0) return lowerLimit;
if (this.compareTo(upperLimit) > 0) return upperLimit;
return this;
}
@notNull
double toDouble() => this;
@notNull
String toStringAsFixed(@notNull int fractionDigits) {
if (fractionDigits < 0 || fractionDigits > 20) {
throw RangeError.range(fractionDigits, 0, 20, "fractionDigits");
}
String result = JS<String>('!', r'#.toFixed(#)', this, fractionDigits);
if (this == 0 && isNegative) return "-$result";
return result;
}
@notNull
String toStringAsExponential([int fractionDigits]) {
String result;
if (fractionDigits != null) {
@notNull
var _fractionDigits = fractionDigits;
if (_fractionDigits < 0 || _fractionDigits > 20) {
throw RangeError.range(_fractionDigits, 0, 20, "fractionDigits");
}
result = JS<String>('!', r'#.toExponential(#)', this, _fractionDigits);
} else {
result = JS<String>('!', r'#.toExponential()', this);
}
if (this == 0 && isNegative) return "-$result";
return result;
}
@notNull
String toStringAsPrecision(@nullCheck int precision) {
if (precision < 1 || precision > 21) {
throw RangeError.range(precision, 1, 21, "precision");
}
String result = JS<String>('!', r'#.toPrecision(#)', this, precision);
if (this == 0 && isNegative) return "-$result";
return result;
}
@notNull
String toRadixString(@nullCheck int radix) {
if (radix < 2 || radix > 36) {
throw RangeError.range(radix, 2, 36, "radix");
}
String result = JS<String>('!', r'#.toString(#)', this, radix);
const int rightParenCode = 0x29;
if (result.codeUnitAt(result.length - 1) != rightParenCode) {
return result;
}
return _handleIEtoString(result);
}
@notNull
static String _handleIEtoString(String result) {
// Result is probably IE's untraditional format for large numbers,
// e.g., "8.0000000000008(e+15)" for 0x8000000000000800.toString(16).
var match = JS<List>(
'', r'/^([\da-z]+)(?:\.([\da-z]+))?\(e\+(\d+)\)$/.exec(#)', result);
if (match == null) {
// Then we don't know how to handle it at all.
throw UnsupportedError("Unexpected toString result: $result");
}
result = JS('!', '#', match[1]);
int exponent = JS("!", "+#", match[3]);
if (match[2] != null) {
result = JS('!', '# + #', result, match[2]);
exponent -= JS<int>('!', '#.length', match[2]);
}
return result + "0" * exponent;
}
// Note: if you change this, also change the function [S].
@notNull
String toString() {
if (this == 0 && JS<bool>('!', '(1 / #) < 0', this)) {
return '-0.0';
} else {
return JS<String>('!', r'"" + (#)', this);
}
}
@notNull
int get hashCode {
int intValue = JS<int>('!', '# | 0', this);
// Fast exit for integers in signed 32-bit range. Masking converts -0.0 to 0
// and ensures that result fits in JavaScript engine's Smi range.
if (this == intValue) return 0x1FFFFFFF & intValue;
// We would like to access the exponent and mantissa as integers but there
// are no JavaScript operations that do this, so use log2-floor-pow-divide
// to extract the values.
num absolute = JS<num>('!', 'Math.abs(#)', this);
num lnAbsolute = JS<num>('!', 'Math.log(#)', absolute);
num log2 = lnAbsolute / ln2;
// Floor via '# | 0' converts NaN to zero so the final result is not NaN.
int floorLog2 = JS<int>('!', '# | 0', log2);
num factor = JS<num>('!', 'Math.pow(2, #)', floorLog2);
num scaled = absolute < 1 ? absolute / factor : factor / absolute;
// [scaled] is in the range [0.5, 1].
// Multiply and truncate to pick up all the mantissa bits. Multiplying by
// 0x20000000000000 (which has 53 zero bits) converts the mantissa into an
// integer. There are interesting subsets where all the bit variance is in
// the most significant bits of the mantissa (e.g. 0.5, 0.625, 0.75), so we
// need to mix in the most significant bits. We do this by scaling with a
// constant that has many bits set to use the multiplier to mix in bits from
// all over the mantissa into low positions.
num rescaled1 = scaled * 0x20000000000000;
num rescaled2 = scaled * 0x0C95A6C285A6C9;
int d1 = JS<int>('!', '# | 0', rescaled1);
int d2 = JS<int>('!', '# | 0', rescaled2);
// Mix in exponent to distinguish e.g. 1.25 from 2.5.
int d3 = floorLog2;
int h = 0x1FFFFFFF & ((d1 + d2) * (601 * 997) + d3 * (1259));
return h;
}
@notNull
JSNumber operator -() => JS<num>('!', r'-#', this);
@notNull
JSNumber operator +(@nullCheck num other) {
return JS<num>('!', '# + #', this, other);
}
@notNull
JSNumber operator -(@nullCheck num other) {
return JS<num>('!', '# - #', this, other);
}
@notNull
double operator /(@nullCheck num other) {
return JS<num>('!', '# / #', this, other);
}
@notNull
JSNumber operator *(@nullCheck num other) {
return JS<num>('!', '# * #', this, other);
}
@notNull
JSNumber operator %(@nullCheck num other) {
// Euclidean Modulo.
num result = JS<num>('!', r'# % #', this, other);
if (result == 0) return (0 as JSNumber); // Make sure we don't return -0.0.
if (result > 0) return result;
if (JS<num>('!', '#', other) < 0) {
return result - JS<num>('!', '#', other);
} else {
return result + JS<num>('!', '#', other);
}
}
@notNull
bool _isInt32(@notNull num value) =>
JS<bool>('!', '(# | 0) === #', value, value);
@notNull
int operator ~/(@nullCheck num other) {
if (_isInt32(this) && _isInt32(other) && 0 != other && -1 != other) {
return JS<int>('!', r'(# / #) | 0', this, other);
} else {
return _tdivSlow(other);
}
}
@notNull
int _tdivSlow(num other) {
return (JS<num>('!', r'# / #', this, other)).toInt();
}
// TODO(ngeoffray): Move the bit operations below to [JSInt] and
// make them take an int. Because this will make operations slower,
// we define these methods on number for now but we need to decide
// the grain at which we do the type checks.
@notNull
int operator <<(@nullCheck num other) {
if (other < 0) throwArgumentErrorValue(other);
return _shlPositive(other);
}
@notNull
int _shlPositive(@notNull num other) {
// JavaScript only looks at the last 5 bits of the shift-amount. Shifting
// by 33 is hence equivalent to a shift by 1.
return JS<bool>('!', r'# > 31', other)
? 0
: JS<int>('!', r'(# << #) >>> 0', this, other);
}
@notNull
int operator >>(@nullCheck num other) {
if (JS<num>('!', '#', other) < 0) throwArgumentErrorValue(other);
return _shrOtherPositive(other);
}
@notNull
int _shrOtherPositive(@notNull num other) {
return JS<num>('!', '#', this) > 0
? _shrBothPositive(other)
// For negative numbers we just clamp the shift-by amount.
// `this` could be negative but not have its 31st bit set.
// The ">>" would then shift in 0s instead of 1s. Therefore
// we cannot simply return 0xFFFFFFFF.
: JS<int>('!', r'(# >> #) >>> 0', this, other > 31 ? 31 : other);
}
@notNull
int _shrBothPositive(@notNull num other) {
return JS<bool>('!', r'# > 31', other)
// JavaScript only looks at the last 5 bits of the shift-amount. In JS
// shifting by 33 is hence equivalent to a shift by 1. Shortcut the
// computation when that happens.
? 0
// Given that `this` is positive we must not use '>>'. Otherwise a
// number that has the 31st bit set would be treated as negative and
// shift in ones.
: JS<int>('!', r'# >>> #', this, other);
}
@notNull
int operator &(@nullCheck num other) {
return JS<int>('!', r'(# & #) >>> 0', this, other);
}
@notNull
int operator |(@nullCheck num other) {
return JS<int>('!', r'(# | #) >>> 0', this, other);
}
@notNull
int operator ^(@nullCheck num other) {
return JS<int>('!', r'(# ^ #) >>> 0', this, other);
}
@notNull
bool operator <(@nullCheck num other) {
return JS<bool>('!', '# < #', this, other);
}
@notNull
bool operator >(@nullCheck num other) {
return JS<bool>('!', '# > #', this, other);
}
@notNull
bool operator <=(@nullCheck num other) {
return JS<bool>('!', '# <= #', this, other);
}
@notNull
bool operator >=(@nullCheck num other) {
return JS<bool>('!', '# >= #', this, other);
}
// int members.
// TODO(jmesserly): all numbers will have these in dynamic dispatch.
// We can fix by checking it at dispatch time but we'd need to structure them
// differently.
@notNull
bool get isEven => (this & 1) == 0;
@notNull
bool get isOdd => (this & 1) == 1;
@notNull
int toUnsigned(@nullCheck int width) {
return this & ((1 << width) - 1);
}
@notNull
int toSigned(@nullCheck int width) {
int signMask = 1 << (width - 1);
return (this & (signMask - 1)) - (this & signMask);
}
@notNull
int get bitLength {
int nonneg = this < 0 ? -this - 1 : this;
int wordBits = 32;
while (nonneg >= 0x100000000) {
nonneg = nonneg ~/ 0x100000000;
wordBits += 32;
}
return wordBits - _clz32(nonneg);
}
@notNull
static int _clz32(@notNull int uint32) {
// TODO(sra): Use `Math.clz32(uint32)` (not available on IE11).
return 32 - _bitCount(_spread(uint32));
}
// Returns pow(this, e) % m.
@notNull
int modPow(@nullCheck int e, @nullCheck int m) {
if (e < 0) throw RangeError.range(e, 0, null, "exponent");
if (m <= 0) throw RangeError.range(m, 1, null, "modulus");
if (e == 0) return 1;
const int maxPreciseInteger = 9007199254740991;
// Reject inputs that are outside the range of integer values that can be
// represented precisely as a Number (double).
if (this < -maxPreciseInteger || this > maxPreciseInteger) {
throw RangeError.range(
this, -maxPreciseInteger, maxPreciseInteger, 'receiver');
}
if (e > maxPreciseInteger) {
throw RangeError.range(e, 0, maxPreciseInteger, 'exponent');
}
if (m > maxPreciseInteger) {
throw RangeError.range(e, 1, maxPreciseInteger, 'modulus');
}
// This is floor(sqrt(maxPreciseInteger)).
const int maxValueThatCanBeSquaredWithoutTruncation = 94906265;
if (m > maxValueThatCanBeSquaredWithoutTruncation) {
// Use BigInt version to avoid truncation in multiplications below. The
// 'maxPreciseInteger' check on [m] ensures that toInt() does not round.
return BigInt.from(this).modPow(BigInt.from(e), BigInt.from(m)).toInt();
}
int b = this;
if (b < 0 || b > m) {
b %= m;
}
int r = 1;
while (e > 0) {
if (e.isOdd) {
r = (r * b) % m;
}
e ~/= 2;
b = (b * b) % m;
}
return r;
}
// If inv is false, returns gcd(x, y).
// If inv is true and gcd(x, y) = 1, returns d, so that c*x + d*y = 1.
// If inv is true and gcd(x, y) != 1, throws Exception("Not coprime").
@notNull
static int _binaryGcd(@notNull int x, @notNull int y, @notNull bool inv) {
int s = 1;
if (!inv) {
while (x.isEven && y.isEven) {
x ~/= 2;
y ~/= 2;
s *= 2;
}
if (y.isOdd) {
var t = x;
x = y;
y = t;
}
}
final bool ac = x.isEven;
int u = x;
int v = y;
int a = 1, b = 0, c = 0, d = 1;
do {
while (u.isEven) {
u ~/= 2;
if (ac) {
if (!a.isEven || !b.isEven) {
a += y;
b -= x;
}
a ~/= 2;
} else if (!b.isEven) {
b -= x;
}
b ~/= 2;
}
while (v.isEven) {
v ~/= 2;
if (ac) {
if (!c.isEven || !d.isEven) {
c += y;
d -= x;
}
c ~/= 2;
} else if (!d.isEven) {
d -= x;
}
d ~/= 2;
}
if (u >= v) {
u -= v;
if (ac) a -= c;
b -= d;
} else {
v -= u;
if (ac) c -= a;
d -= b;
}
} while (u != 0);
if (!inv) return s * v;
if (v != 1) throw Exception("Not coprime");
if (d < 0) {
d += x;
if (d < 0) d += x;
} else if (d > x) {
d -= x;
if (d > x) d -= x;
}
return d;
}
// Returns 1/this % m, with m > 0.
@notNull
int modInverse(@nullCheck int m) {
if (m <= 0) throw RangeError.range(m, 1, null, "modulus");
if (m == 1) return 0;
int t = this;
if ((t < 0) || (t >= m)) t %= m;
if (t == 1) return 1;
if ((t == 0) || (t.isEven && m.isEven)) {
throw Exception("Not coprime");
}
return _binaryGcd(m, t, true);
}
// Returns gcd of abs(this) and abs(other).
@notNull
int gcd(@nullCheck int other) {
int x = this.abs();
int y = other.abs();
if (x == 0) return y;
if (y == 0) return x;
if ((x == 1) || (y == 1)) return 1;
return _binaryGcd(x, y, false);
}
// Assumes i is <= 32-bit and unsigned.
@notNull
static int _bitCount(@notNull int i) {
// See "Hacker's Delight", section 5-1, "Counting 1-Bits".
// The basic strategy is to use "divide and conquer" to
// add pairs (then quads, etc.) of bits together to obtain
// sub-counts.
//
// A straightforward approach would look like:
//
// i = (i & 0x55555555) + ((i >> 1) & 0x55555555);
// i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
// i = (i & 0x0F0F0F0F) + ((i >> 4) & 0x0F0F0F0F);
// i = (i & 0x00FF00FF) + ((i >> 8) & 0x00FF00FF);
// i = (i & 0x0000FFFF) + ((i >> 16) & 0x0000FFFF);
//
// The code below removes unnecessary &'s and uses a
// trick to remove one instruction in the first line.
i = _shru(i, 0) - (_shru(i, 1) & 0x55555555);
i = (i & 0x33333333) + (_shru(i, 2) & 0x33333333);
i = 0x0F0F0F0F & (i + _shru(i, 4));
i += _shru(i, 8);
i += _shru(i, 16);
return (i & 0x0000003F);
}
@notNull
static int _shru(int value, int shift) =>
JS<int>('!', '# >>> #', value, shift);
@notNull
static int _shrs(int value, int shift) =>
JS<int>('!', '# >> #', value, shift);
@notNull
static int _ors(int a, int b) => JS<int>('!', '# | #', a, b);
// Assumes i is <= 32-bit
@notNull
static int _spread(@notNull int i) {
i = _ors(i, _shrs(i, 1));
i = _ors(i, _shrs(i, 2));
i = _ors(i, _shrs(i, 4));
i = _ors(i, _shrs(i, 8));
i = _shru(_ors(i, _shrs(i, 16)), 0);
return i;
}
@notNull
int operator ~() => JS<int>('!', r'(~#) >>> 0', this);
}

View file

@ -0,0 +1,49 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/// dart2js "primitives", that is, features that cannot be implemented without
/// access to JavaScript features.
library dart2js._js_primitives;
import 'dart:_foreign_helper' show JS;
/**
* This is the low-level method that is used to implement [print]. It is
* possible to override this function from JavaScript by defining a function in
* JavaScript called "dartPrint".
*
* Notice that it is also possible to intercept calls to [print] from within a
* Dart program using zones. This means that there is no guarantee that a call
* to print ends in this method.
*/
void printString(String string) {
if (JS<bool>('!', r'typeof dartPrint == "function"')) {
// Support overriding print from JavaScript.
JS('void', r'dartPrint(#)', string);
return;
}
// Inside browser or nodejs.
if (JS<bool>('!', r'typeof console == "object"') &&
JS<bool>('!', r'typeof console.log != "undefined"')) {
JS('void', r'console.log(#)', string);
return;
}
// Don't throw inside IE, the console is only defined if dev tools is open.
if (JS<bool>('!', r'typeof window == "object"')) {
return;
}
// Running in d8, the V8 developer shell, or in Firefox' js-shell.
if (JS<bool>('!', r'typeof print == "function"')) {
JS('void', r'print(#)', string);
return;
}
// This is somewhat nasty, but we don't want to drag in a bunch of
// dependencies to handle a situation that cannot happen. So we
// avoid using Dart [:throw:] and Dart [toString].
JS('void', 'throw "Unable to print message: " + String(#)', string);
}

View file

@ -0,0 +1,27 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart._js_helper;
// TODO(leafp): Maybe get rid of this? Currently used by the interceptors
// library, but that should probably be culled as well.
Type getRuntimeType(var object) =>
JS('Type|null', 'dart.getReifiedType(#)', object);
/// Returns the property [index] of the JavaScript array [array].
getIndex(var array, int index) {
assert(isJsArray(array));
return JS('var', r'#[#]', array, index);
}
/// Returns the length of the JavaScript array [array].
int getLength(var array) {
assert(isJsArray(array));
return JS<int>('!', r'#.length', array);
}
/// Returns whether [value] is a JavaScript array.
bool isJsArray(var value) {
return value is JSArray;
}

View file

@ -0,0 +1,507 @@
// 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.
part of dart._interceptors;
/**
* The interceptor class for [String]. The compiler recognizes this
* class as an interceptor, and changes references to [:this:] to
* actually use the receiver of the method, which is generated as an extra
* argument added to each member.
*/
@JsPeerInterface(name: 'String')
class JSString extends Interceptor implements String, JSIndexable<String> {
const JSString();
@notNull
int codeUnitAt(@nullCheck int index) {
// Suppress 2nd null check on index and null check on length
// (JS String.length cannot be null).
final len = this.length;
if (index < 0 || index >= len) {
throw RangeError.index(index, this, 'index', null, len);
}
return JS<int>('!', r'#.charCodeAt(#)', this, index);
}
@notNull
Iterable<Match> allMatches(@nullCheck String string,
[@nullCheck int start = 0]) {
final len = string.length;
if (0 > start || start > len) {
throw RangeError.range(start, 0, len);
}
return allMatchesInStringUnchecked(this, string, start);
}
Match matchAsPrefix(@nullCheck String string, [@nullCheck int start = 0]) {
int stringLength = JS('!', '#.length', string);
if (start < 0 || start > stringLength) {
throw RangeError.range(start, 0, stringLength);
}
int thisLength = JS('!', '#.length', this);
if (start + thisLength > stringLength) return null;
for (int i = 0; i < thisLength; i++) {
if (string.codeUnitAt(start + i) != this.codeUnitAt(i)) {
return null;
}
}
return StringMatch(start, string, this);
}
@notNull
String operator +(@nullCheck String other) {
return JS<String>('!', r'# + #', this, other);
}
@notNull
bool endsWith(@nullCheck String other) {
var otherLength = other.length;
var thisLength = this.length;
if (otherLength > thisLength) return false;
return other == substring(thisLength - otherLength);
}
@notNull
String replaceAll(Pattern from, @nullCheck String to) {
return stringReplaceAllUnchecked(this, from, to);
}
@notNull
String replaceAllMapped(Pattern from, String convert(Match match)) {
return this.splitMapJoin(from, onMatch: convert);
}
@notNull
String splitMapJoin(Pattern from,
{String onMatch(Match match), String onNonMatch(String nonMatch)}) {
return stringReplaceAllFuncUnchecked(this, from, onMatch, onNonMatch);
}
@notNull
String replaceFirst(Pattern from, @nullCheck String to,
[@nullCheck int startIndex = 0]) {
RangeError.checkValueInInterval(startIndex, 0, this.length, "startIndex");
return stringReplaceFirstUnchecked(this, from, to, startIndex);
}
@notNull
String replaceFirstMapped(
Pattern from, @nullCheck String replace(Match match),
[@nullCheck int startIndex = 0]) {
RangeError.checkValueInInterval(startIndex, 0, this.length, "startIndex");
return stringReplaceFirstMappedUnchecked(this, from, replace, startIndex);
}
@notNull
List<String> split(@nullCheck Pattern pattern) {
if (pattern is String) {
return JSArray.of(JS('', r'#.split(#)', this, pattern));
} else if (pattern is JSSyntaxRegExp && regExpCaptureCount(pattern) == 0) {
var re = regExpGetNative(pattern);
return JSArray.of(JS('', r'#.split(#)', this, re));
} else {
return _defaultSplit(pattern);
}
}
@notNull
String replaceRange(
@nullCheck int start, int end, @nullCheck String replacement) {
end = RangeError.checkValidRange(start, end, this.length);
return stringReplaceRangeUnchecked(this, start, end, replacement);
}
@notNull
List<String> _defaultSplit(Pattern pattern) {
List<String> result = <String>[];
// End of most recent match. That is, start of next part to add to result.
int start = 0;
// Length of most recent match.
// Set >0, so no match on the empty string causes the result to be [""].
int length = 1;
for (var match in pattern.allMatches(this)) {
@notNull
int matchStart = match.start;
@notNull
int matchEnd = match.end;
length = matchEnd - matchStart;
if (length == 0 && start == matchStart) {
// An empty match right after another match is ignored.
// This includes an empty match at the start of the string.
continue;
}
int end = matchStart;
result.add(this.substring(start, end));
start = matchEnd;
}
if (start < this.length || length > 0) {
// An empty match at the end of the string does not cause a "" at the end.
// A non-empty match ending at the end of the string does add a "".
result.add(this.substring(start));
}
return result;
}
@notNull
bool startsWith(Pattern pattern, [@nullCheck int index = 0]) {
// Suppress null check on length and all but the first
// reference to index.
int length = JS<int>('!', '#.length', this);
if (index < 0 || JS<int>('!', '#', index) > length) {
throw RangeError.range(index, 0, this.length);
}
if (pattern is String) {
String other = pattern;
int otherLength = JS<int>('!', '#.length', other);
int endIndex = index + otherLength;
if (endIndex > length) return false;
return other ==
JS<String>('!', r'#.substring(#, #)', this, index, endIndex);
}
return pattern.matchAsPrefix(this, index) != null;
}
@notNull
String substring(@nullCheck int startIndex, [int _endIndex]) {
var length = this.length;
final endIndex = _endIndex ?? length;
if (startIndex < 0) throw RangeError.value(startIndex);
if (startIndex > endIndex) throw RangeError.value(startIndex);
if (endIndex > length) throw RangeError.value(endIndex);
return JS<String>('!', r'#.substring(#, #)', this, startIndex, endIndex);
}
@notNull
String toLowerCase() {
return JS<String>('!', r'#.toLowerCase()', this);
}
@notNull
String toUpperCase() {
return JS<String>('!', r'#.toUpperCase()', this);
}
// Characters with Whitespace property (Unicode 6.3).
// 0009..000D ; White_Space # Cc <control-0009>..<control-000D>
// 0020 ; White_Space # Zs SPACE
// 0085 ; White_Space # Cc <control-0085>
// 00A0 ; White_Space # Zs NO-BREAK SPACE
// 1680 ; White_Space # Zs OGHAM SPACE MARK
// 2000..200A ; White_Space # Zs EN QUAD..HAIR SPACE
// 2028 ; White_Space # Zl LINE SEPARATOR
// 2029 ; White_Space # Zp PARAGRAPH SEPARATOR
// 202F ; White_Space # Zs NARROW NO-BREAK SPACE
// 205F ; White_Space # Zs MEDIUM MATHEMATICAL SPACE
// 3000 ; White_Space # Zs IDEOGRAPHIC SPACE
//
// BOM: 0xFEFF
@notNull
static bool _isWhitespace(@notNull int codeUnit) {
// Most codeUnits should be less than 256. Special case with a smaller
// switch.
if (codeUnit < 256) {
switch (codeUnit) {
case 0x09:
case 0x0A:
case 0x0B:
case 0x0C:
case 0x0D:
case 0x20:
case 0x85:
case 0xA0:
return true;
default:
return false;
}
}
switch (codeUnit) {
case 0x1680:
case 0x2000:
case 0x2001:
case 0x2002:
case 0x2003:
case 0x2004:
case 0x2005:
case 0x2006:
case 0x2007:
case 0x2008:
case 0x2009:
case 0x200A:
case 0x2028:
case 0x2029:
case 0x202F:
case 0x205F:
case 0x3000:
case 0xFEFF:
return true;
default:
return false;
}
}
/// Finds the index of the first non-whitespace character, or the
/// end of the string. Start looking at position [index].
@notNull
static int _skipLeadingWhitespace(String string, @nullCheck int index) {
const int SPACE = 0x20;
const int CARRIAGE_RETURN = 0x0D;
var stringLength = string.length;
while (index < stringLength) {
int codeUnit = string.codeUnitAt(index);
if (codeUnit != SPACE &&
codeUnit != CARRIAGE_RETURN &&
!_isWhitespace(codeUnit)) {
break;
}
index++;
}
return index;
}
/// Finds the index after the last non-whitespace character, or 0.
/// Start looking at position [index - 1].
@notNull
static int _skipTrailingWhitespace(String string, @nullCheck int index) {
const int SPACE = 0x20;
const int CARRIAGE_RETURN = 0x0D;
while (index > 0) {
int codeUnit = string.codeUnitAt(index - 1);
if (codeUnit != SPACE &&
codeUnit != CARRIAGE_RETURN &&
!_isWhitespace(codeUnit)) {
break;
}
index--;
}
return index;
}
// Dart2js can't use JavaScript trim directly,
// because JavaScript does not trim
// the NEXT LINE (NEL) character (0x85).
@notNull
String trim() {
const int NEL = 0x85;
// Start by doing JS trim. Then check if it leaves a NEL at
// either end of the string.
String result = JS('!', '#.trim()', this);
final length = result.length;
if (length == 0) return result;
int firstCode = result.codeUnitAt(0);
int startIndex = 0;
if (firstCode == NEL) {
startIndex = _skipLeadingWhitespace(result, 1);
if (startIndex == length) return "";
}
int endIndex = length;
// We know that there is at least one character that is non-whitespace.
// Therefore we don't need to verify that endIndex > startIndex.
int lastCode = result.codeUnitAt(endIndex - 1);
if (lastCode == NEL) {
endIndex = _skipTrailingWhitespace(result, endIndex - 1);
}
if (startIndex == 0 && endIndex == length) return result;
return JS<String>('!', r'#.substring(#, #)', result, startIndex, endIndex);
}
// Dart2js can't use JavaScript trimLeft directly,
// because it is not in ES5, so not every browser implements it,
// and because those that do will not trim the NEXT LINE character (0x85).
@notNull
String trimLeft() {
const int NEL = 0x85;
// Start by doing JS trim. Then check if it leaves a NEL at
// the beginning of the string.
String result;
int startIndex = 0;
if (JS<bool>('!', 'typeof #.trimLeft != "undefined"', this)) {
result = JS<String>('!', '#.trimLeft()', this);
if (result.length == 0) return result;
int firstCode = result.codeUnitAt(0);
if (firstCode == NEL) {
startIndex = _skipLeadingWhitespace(result, 1);
}
} else {
result = this;
startIndex = _skipLeadingWhitespace(this, 0);
}
if (startIndex == 0) return result;
if (startIndex == result.length) return "";
return JS<String>('!', r'#.substring(#)', result, startIndex);
}
// Dart2js can't use JavaScript trimRight directly,
// because it is not in ES5 and because JavaScript does not trim
// the NEXT LINE character (0x85).
@notNull
String trimRight() {
const int NEL = 0x85;
// Start by doing JS trim. Then check if it leaves a NEL or BOM at
// the end of the string.
String result;
@notNull
int endIndex = 0;
// trimRight is implemented by Firefox and Chrome/Blink,
// so use it if it is there.
if (JS<bool>('!', 'typeof #.trimRight != "undefined"', this)) {
result = JS<String>('!', '#.trimRight()', this);
endIndex = result.length;
if (endIndex == 0) return result;
int lastCode = result.codeUnitAt(endIndex - 1);
if (lastCode == NEL) {
endIndex = _skipTrailingWhitespace(result, endIndex - 1);
}
} else {
result = this;
endIndex = _skipTrailingWhitespace(this, this.length);
}
if (endIndex == result.length) return result;
if (endIndex == 0) return "";
return JS<String>('!', r'#.substring(#, #)', result, 0, endIndex);
}
@notNull
String operator *(@nullCheck int times) {
if (0 >= times) return '';
if (times == 1 || this.length == 0) return this;
if (times != JS<int>('!', '# >>> 0', times)) {
// times >= 2^32. We can't create a string that big.
throw const OutOfMemoryError();
}
var result = '';
String s = this;
while (true) {
if (times & 1 == 1) result = s + result;
times = JS<int>('!', '# >>> 1', times);
if (times == 0) break;
s += s;
}
return result;
}
@notNull
String padLeft(@nullCheck int width, [String padding = ' ']) {
int delta = width - this.length;
if (delta <= 0) return this;
return padding * delta + this;
}
@notNull
String padRight(@nullCheck int width, [String padding = ' ']) {
int delta = width - this.length;
if (delta <= 0) return this;
return this + padding * delta;
}
@notNull
List<int> get codeUnits => CodeUnits(this);
@notNull
Runes get runes => Runes(this);
@notNull
int indexOf(@nullCheck Pattern pattern, [@nullCheck int start = 0]) {
if (start < 0 || start > this.length) {
throw RangeError.range(start, 0, this.length);
}
if (pattern is String) {
return stringIndexOfStringUnchecked(this, pattern, start);
}
if (pattern is JSSyntaxRegExp) {
JSSyntaxRegExp re = pattern;
Match match = firstMatchAfter(re, this, start);
return (match == null) ? -1 : match.start;
}
var length = this.length;
for (int i = start; i <= length; i++) {
if (pattern.matchAsPrefix(this, i) != null) return i;
}
return -1;
}
@notNull
int lastIndexOf(@nullCheck Pattern pattern, [int _start]) {
var length = this.length;
var start = _start ?? length;
if (start < 0 || start > length) {
throw RangeError.range(start, 0, length);
}
if (pattern is String) {
String other = pattern;
if (start + other.length > length) {
start = length - other.length;
}
return stringLastIndexOfUnchecked(this, other, start);
}
for (int i = start; i >= 0; i--) {
if (pattern.matchAsPrefix(this, i) != null) return i;
}
return -1;
}
@notNull
bool contains(@nullCheck Pattern other, [@nullCheck int startIndex = 0]) {
if (startIndex < 0 || startIndex > this.length) {
throw RangeError.range(startIndex, 0, this.length);
}
return stringContainsUnchecked(this, other, startIndex);
}
@notNull
bool get isEmpty => JS<int>('!', '#.length', this) == 0;
@notNull
bool get isNotEmpty => !isEmpty;
@notNull
int compareTo(@nullCheck String other) {
return this == other ? 0 : JS<bool>('!', r'# < #', this, other) ? -1 : 1;
}
// Note: if you change this, also change the function [S].
@notNull
String toString() => this;
/**
* This is the [Jenkins hash function][1] but using masking to keep
* values in SMI range.
*
* [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function
*/
@notNull
int get hashCode {
// TODO(ahe): This method shouldn't have to use JS. Update when our
// optimizations are smarter.
int hash = 0;
int length = JS('!', '#.length', this);
for (int i = 0; i < length; i++) {
hash = 0x1fffffff & (hash + JS<int>('!', r'#.charCodeAt(#)', this, i));
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
hash = JS<int>('!', '# ^ (# >> 6)', hash, hash);
}
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
hash = JS<int>('!', '# ^ (# >> 11)', hash, hash);
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
@notNull
Type get runtimeType => String;
@notNull
final int length;
@notNull
String operator [](@nullCheck int index) {
if (index >= JS<int>('!', '#.length', this) || index < 0) {
throw diagnoseIndexError(this, index);
}
return JS<String>('!', '#[#]', this, index);
}
}

View file

@ -0,0 +1,278 @@
// Copyright (c) 2017, 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.
// Efficient JavaScript based implementation of a linked hash map used as a
// backing map for constant maps and the [LinkedHashMap] patch
part of dart._js_helper;
abstract class InternalMap<K, V> extends MapBase<K, V>
implements LinkedHashMap<K, V>, HashMap<K, V> {
@notNull
get _map;
@notNull
int get _modifications;
void forEach(void action(K key, V value)) {
int modifications = _modifications;
for (var entry in JS('Iterable', '#.entries()', _map)) {
action(JS('', '#[0]', entry), JS('', '#[1]', entry));
if (modifications != _modifications) {
throw ConcurrentModificationError(this);
}
}
}
}
/// A linked hash map implementation based on ES6 Map.
///
/// Items that can use identity semantics are stored directly in the backing
/// map.
///
/// Items that have a custom equality/hashCode are first canonicalized by
/// looking up the canonical key by its hashCode.
class LinkedMap<K, V> extends InternalMap<K, V> {
/// The backing store for this map.
///
/// Keys that use identity equality are stored directly. For other types of
/// keys, we first look them up (by hashCode) in the [_keyMap] map, then
/// we lookup the key in this map.
@notNull
final _map = JS('', 'new Map()');
/// Items that use custom equality semantics.
///
/// This maps from the item's hashCode to the canonical key, which is then
/// used to lookup the item in [_map]. Keeping the data in our primary backing
/// map gives us the ordering semantics requred by [LinkedHashMap], while
/// also providing convenient access to keys/values.
@notNull
final _keyMap = JS('', 'new Map()');
// We track the number of modifications done to the key set of the
// hash map to be able to throw when the map is modified while being
// iterated over.
//
// Value cycles after 2^30 modifications so that modification counts are
// always unboxed (Smi) values. Modification detection will be missed if you
// make exactly some multiple of 2^30 modifications between advances of an
// iterator.
@notNull
int _modifications = 0;
LinkedMap();
/// Called by generated code for a map literal.
LinkedMap.from(JSArray entries) {
var map = _map;
var keyMap = _keyMap;
for (int i = 0, n = JS('!', '#.length', entries); i < n; i += 2) {
K key = JS('', '#[#]', entries, i);
V value = JS('', '#[#]', entries, i + 1);
if (key == null) {
key = null;
} else if (JS<bool>('!', '#[#] !== #', key,
dart.extensionSymbol('_equals'), dart.identityEquals)) {
key = putLinkedMapKey(key, keyMap);
}
JS('', '#.set(#, #)', map, key, value);
}
}
@notNull
int get length => JS<int>('!', '#.size', _map);
@notNull
bool get isEmpty => JS<bool>('!', '#.size == 0', _map);
@notNull
bool get isNotEmpty => JS<bool>('!', '#.size != 0', _map);
Iterable<K> get keys => _JSMapIterable<K>(this, true);
Iterable<V> get values => _JSMapIterable<V>(this, false);
@notNull
bool containsKey(Object key) {
if (key == null) {
key = null;
} else if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
dart.identityEquals)) {
@notNull
var k = key;
var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, k.hashCode);
if (buckets != null) {
for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
k = JS('', '#[#]', buckets, i);
if (k == key) return true;
}
}
return false;
}
return JS<bool>('!', '#.has(#)', _map, key);
}
bool containsValue(Object value) {
for (var v in JS('', '#.values()', _map)) {
if (v == value) return true;
}
return false;
}
void addAll(Map<K, V> other) {
var map = _map;
int length = JS('', '#.size', map);
other.forEach((K key, V value) {
if (key == null) {
key = null;
} else if (JS<bool>('!', '#[#] !== #', key,
dart.extensionSymbol('_equals'), dart.identityEquals)) {
key = putLinkedMapKey(key, _keyMap);
}
JS('', '#.set(#, #)', _map, key, value);
});
if (length != JS<int>('!', '#.size', map)) {
_modifications = (_modifications + 1) & 0x3ffffff;
}
}
V operator [](Object key) {
if (key == null) {
key = null;
} else if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
dart.identityEquals)) {
@notNull
var k = key;
var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, k.hashCode);
if (buckets != null) {
for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
k = JS('', '#[#]', buckets, i);
if (k == key) return JS('', '#.get(#)', _map, k);
}
}
return null;
}
V value = JS('', '#.get(#)', _map, key);
return value == null ? null : value; // coerce undefined to null.
}
void operator []=(K key, V value) {
if (key == null) {
key = null;
} else if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
dart.identityEquals)) {
key = putLinkedMapKey(key, _keyMap);
}
var map = _map;
int length = JS('', '#.size', map);
JS('', '#.set(#, #)', map, key, value);
if (length != JS<int>('!', '#.size', map)) {
_modifications = (_modifications + 1) & 0x3ffffff;
}
}
V putIfAbsent(K key, V ifAbsent()) {
var map = _map;
if (key == null) {
key = null;
if (JS<bool>('!', '#.has(null)', map)) return JS('', '#.get(null)', map);
} else if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
dart.identityEquals)) {
@notNull
K k = key;
var hash = JS<int>('!', '# & 0x3ffffff', k.hashCode);
var buckets = JS('', '#.get(#)', _keyMap, hash);
if (buckets == null) {
JS('', '#.set(#, [#])', _keyMap, hash, key);
} else {
for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
k = JS('', '#[#]', buckets, i);
if (k == key) return JS('', '#.get(#)', map, k);
}
JS('', '#.push(#)', buckets, key);
}
} else if (JS<bool>('!', '#.has(#)', map, key)) {
return JS('', '#.get(#)', map, key);
}
V value = ifAbsent();
if (value == null) value = null; // coerce undefined to null.
JS('', '#.set(#, #)', map, key, value);
_modifications = (_modifications + 1) & 0x3ffffff;
return value;
}
V remove(Object key) {
if (key == null) {
key = null;
} else if (JS<bool>('!', '#[#] !== #', key, dart.extensionSymbol('_equals'),
dart.identityEquals)) {
@notNull
var k = key;
var hash = JS<int>('!', '# & 0x3ffffff', k.hashCode);
var buckets = JS('', '#.get(#)', _keyMap, hash);
if (buckets == null) return null; // not found
for (int i = 0, n = JS('!', '#.length', buckets);;) {
k = JS('', '#[#]', buckets, i);
if (k == key) {
key = k;
if (n == 1) {
JS('', '#.delete(#)', _keyMap, hash);
} else {
JS('', '#.splice(#, 1)', buckets, i);
}
break;
}
if (++i >= n) return null; // not found
}
}
var map = _map;
V value = JS('', '#.get(#)', map, key);
if (JS<bool>('!', '#.delete(#)', map, key)) {
_modifications = (_modifications + 1) & 0x3ffffff;
}
return value == null ? null : value; // coerce undefined to null.
}
void clear() {
var map = _map;
if (JS<int>('!', '#.size', map) > 0) {
JS('', '#.clear()', map);
JS('', '#.clear()', _keyMap);
_modifications = (_modifications + 1) & 0x3ffffff;
}
}
}
@NoReifyGeneric()
K putLinkedMapKey<K>(@notNull K key, keyMap) {
var hash = JS<int>('!', '# & 0x3ffffff', key.hashCode);
var buckets = JS('', '#.get(#)', keyMap, hash);
if (buckets == null) {
JS('', '#.set(#, [#])', keyMap, hash, key);
return key;
}
for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
@notNull
K k = JS('', '#[#]', buckets, i);
if (k == key) return k;
}
JS('', '#.push(#)', buckets, key);
return key;
}
class ImmutableMap<K, V> extends LinkedMap<K, V> {
ImmutableMap.from(JSArray entries) : super.from(entries);
void operator []=(Object key, Object value) {
throw _unsupported();
}
void addAll(Object other) => throw _unsupported();
void clear() => throw _unsupported();
V remove(Object key) => throw _unsupported();
V putIfAbsent(Object key, Object ifAbsent()) => throw _unsupported();
static Error _unsupported() =>
UnsupportedError("Cannot modify unmodifiable map");
}

View file

@ -0,0 +1,8 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/**
* Helps dealing with reflection in the case that the source code has been
* changed as a result of compiling with dart2dart.
*/
library dart._mirror_helper;

View file

@ -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.
part of dart._js_helper;
// Obsolete in dart dev compiler. Added only so that the same version of
// dart:html can be used in dart2js an dev compiler.
F convertDartClosureToJS<F>(F closure, int arity) {
return closure;
}
// Warning: calls to these methods need to be removed before custom elements
// and cross-frame dom objects behave correctly in ddc
// https://github.com/dart-lang/sdk/issues/28326
setNativeSubclassDispatchRecord(proto, interceptor) {}
findDispatchTagForInterceptorClass(interceptorClassConstructor) {}
makeLeafDispatchRecord(interceptor) {}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,17 @@
The files in this directory polyfill some of the functionality that browsers
provide. When running command-line JS evaluators it is frequently necessary to
execute the preambles before executing the output of dart2js.
=Usage=
- d8:
d8 <sdk>/lib/_internal/compiler/js_lib/preambles/d8.js <output>.js
- jsshell:
jsshell -f <sdk>/lib/_internal/compiler/js_lib/preambles/d8.js -f <output>.js
- node.js:
The d8 preamble file works for most programs.
Unfortunately we are not aware of any easy way to provide multiple input files
to node. It seems to be necessary to concatenate the d8 preamble and the
dart2js output.

View file

@ -0,0 +1,291 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Javascript preamble, that lets the output of dart2js run on V8's d8 shell.
// Node wraps files and provides them with a different `this`. The global
// `this` can be accessed through `global`.
var self = this;
if (typeof global != "undefined") self = global; // Node.js.
(function(self) {
// Using strict mode to avoid accidentally defining global variables.
"use strict"; // Should be first statement of this function.
// Location (Uri.base)
var workingDirectory;
// TODO(sgjesse): This does not work on Windows.
if (typeof os == "object" && "system" in os) {
// V8.
workingDirectory = os.system("pwd");
var length = workingDirectory.length;
if (workingDirectory[length - 1] == '\n') {
workingDirectory = workingDirectory.substring(0, length - 1);
}
} else if (typeof process != "undefined" &&
typeof process.cwd == "function") {
// Node.js.
workingDirectory = process.cwd();
}
self.location = { href: "file://" + workingDirectory + "/" };
// Event loop.
// Task queue as cyclic list queue.
var taskQueue = new Array(8); // Length is power of 2.
var head = 0;
var tail = 0;
var mask = taskQueue.length - 1;
function addTask(elem) {
taskQueue[head] = elem;
head = (head + 1) & mask;
if (head == tail) _growTaskQueue();
}
function removeTask() {
if (head == tail) return;
var result = taskQueue[tail];
taskQueue[tail] = undefined;
tail = (tail + 1) & mask;
return result;
}
function _growTaskQueue() {
// head == tail.
var length = taskQueue.length;
var split = head;
taskQueue.length = length * 2;
if (split * 2 < length) { // split < length / 2
for (var i = 0; i < split; i++) {
taskQueue[length + i] = taskQueue[i];
taskQueue[i] = undefined;
}
head += length;
} else {
for (var i = split; i < length; i++) {
taskQueue[length + i] = taskQueue[i];
taskQueue[i] = undefined;
}
tail += length;
}
mask = taskQueue.length - 1;
}
// Mapping from timer id to timer function.
// The timer id is written on the function as .$timerId.
// That field is cleared when the timer is cancelled, but it is not returned
// from the queue until its time comes.
var timerIds = {};
var timerIdCounter = 1; // Counter used to assign ids.
// Zero-timer queue as simple array queue using push/shift.
var zeroTimerQueue = [];
function addTimer(f, ms) {
var id = timerIdCounter++;
f.$timerId = id;
timerIds[id] = f;
if (ms == 0 && !isNextTimerDue()) {
zeroTimerQueue.push(f);
} else {
addDelayedTimer(f, ms);
}
return id;
}
function nextZeroTimer() {
while (zeroTimerQueue.length > 0) {
var action = zeroTimerQueue.shift();
if (action.$timerId !== undefined) return action;
}
}
function nextEvent() {
var action = removeTask();
if (action) {
return action;
}
do {
action = nextZeroTimer();
if (action) break;
var nextList = nextDelayedTimerQueue();
if (!nextList) {
return;
}
var newTime = nextList.shift();
advanceTimeTo(newTime);
zeroTimerQueue = nextList;
} while (true)
var id = action.$timerId;
clearTimerId(action, id);
return action;
}
// Mocking time.
var timeOffset = 0;
var now = function() {
// Install the mock Date object only once.
// Following calls to "now" will just use the new (mocked) Date.now
// method directly.
installMockDate();
now = Date.now;
return Date.now();
};
var originalDate = Date;
var originalNow = originalDate.now;
function advanceTimeTo(time) {
var now = originalNow();
if (timeOffset < time - now) {
timeOffset = time - now;
}
}
function installMockDate() {
var NewDate = function Date(Y, M, D, h, m, s, ms) {
if (this instanceof Date) {
// Assume a construct call.
switch (arguments.length) {
case 0: return new originalDate(originalNow() + timeOffset);
case 1: return new originalDate(Y);
case 2: return new originalDate(Y, M);
case 3: return new originalDate(Y, M, D);
case 4: return new originalDate(Y, M, D, h);
case 5: return new originalDate(Y, M, D, h, m);
case 6: return new originalDate(Y, M, D, h, m, s);
default: return new originalDate(Y, M, D, h, m, s, ms);
}
}
return new originalDate(originalNow() + timeOffset).toString();
};
NewDate.UTC = originalDate.UTC;
NewDate.parse = originalDate.parse;
NewDate.now = function now() { return originalNow() + timeOffset; };
NewDate.prototype = originalDate.prototype;
originalDate.prototype.constructor = NewDate;
Date = NewDate;
}
// Heap priority queue with key index.
// Each entry is list of [timeout, callback1 ... callbackn].
var timerHeap = [];
var timerIndex = {};
function addDelayedTimer(f, ms) {
var timeout = now() + ms;
var timerList = timerIndex[timeout];
if (timerList == null) {
timerList = [timeout, f];
timerIndex[timeout] = timerList;
var index = timerHeap.length;
timerHeap.length += 1;
bubbleUp(index, timeout, timerList);
} else {
timerList.push(f);
}
}
function isNextTimerDue() {
if (timerHeap.length == 0) return false;
var head = timerHeap[0];
return head[0] < originalNow() + timeOffset;
}
function nextDelayedTimerQueue() {
if (timerHeap.length == 0) return null;
var result = timerHeap[0];
var last = timerHeap.pop();
if (timerHeap.length > 0) {
bubbleDown(0, last[0], last);
}
return result;
}
function bubbleUp(index, key, value) {
while (index != 0) {
var parentIndex = (index - 1) >> 1;
var parent = timerHeap[parentIndex];
var parentKey = parent[0];
if (key > parentKey) break;
timerHeap[index] = parent;
index = parentIndex;
}
timerHeap[index] = value;
}
function bubbleDown(index, key, value) {
while (true) {
var leftChildIndex = index * 2 + 1;
if (leftChildIndex >= timerHeap.length) break;
var minChildIndex = leftChildIndex;
var minChild = timerHeap[leftChildIndex];
var minChildKey = minChild[0];
var rightChildIndex = leftChildIndex + 1;
if (rightChildIndex < timerHeap.length) {
var rightChild = timerHeap[rightChildIndex];
var rightKey = rightChild[0];
if (rightKey < minChildKey) {
minChildIndex = rightChildIndex;
minChild = rightChild;
minChildKey = rightKey;
}
}
if (minChildKey > key) break;
timerHeap[index] = minChild;
index = minChildIndex;
}
timerHeap[index] = value;
}
function addInterval(f, ms) {
var id = timerIdCounter++;
function repeat() {
// Reactivate with the same id.
repeat.$timerId = id;
timerIds[id] = repeat;
addDelayedTimer(repeat, ms);
f();
}
repeat.$timerId = id;
timerIds[id] = repeat;
addDelayedTimer(repeat, ms);
return id;
}
function cancelTimer(id) {
var f = timerIds[id];
if (f == null) return;
clearTimerId(f, id);
}
function clearTimerId(f, id) {
f.$timerId = undefined;
delete timerIds[id];
}
function eventLoop(action) {
while (action) {
try {
action();
} catch (e) {
if (typeof onerror == "function") {
onerror(e, null, -1);
} else {
throw e;
}
}
action = nextEvent();
}
}
// Global properties. "self" refers to the global object, so adding a
// property to "self" defines a global variable.
self.dartMainRunner = function(main, args) {
// Initialize.
var action = function() { main(args); }
eventLoop(action);
};
self.setTimeout = addTimer;
self.clearTimeout = cancelTimer;
self.setInterval = addInterval;
self.clearInterval = cancelTimer;
self.scheduleImmediate = addTask;
self.self = self;
})(self);

View file

@ -0,0 +1,19 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Javascript preamble, that lets the output of dart2js run on JSShell.
(function(self) {
// Using strict mode to avoid accidentally defining global variables.
"use strict"; // Should be first statement of this function.
// Location (Uri.base)
var workingDirectory = environment["PWD"];
self.location = { href: "file://" + workingDirectory + "/" };
// Global properties. "self" refers to the global object, so adding a
// property to "self" defines a global variable.
self.self = self;
})(this)

View file

@ -0,0 +1,135 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/// This file supports profiling dynamic calls.
part of dart._debugger;
class _MethodStats {
final String typeName;
final String frame;
double count;
_MethodStats(this.typeName, this.frame) {
count = 0.0;
}
}
class _CallMethodRecord {
var jsError;
var type;
_CallMethodRecord(this.jsError, this.type);
}
/// Size for the random sample of dynamic calls.
int _callRecordSampleSize = 5000;
/// If the number of dynamic calls exceeds [_callRecordSampleSize] this list
/// will represent a random sample of the dynamic calls made.
List<_CallMethodRecord> _callMethodRecords = List();
/// If the number of dynamic calls exceeds [_callRecordSampleSize] this value
/// will be greater than [_callMethodRecords.length].
int _totalCallRecords = 0;
/// Minimum number of samples to consider a profile entry relevant.
/// This could be set a lot higher. We set this value so users are not
/// confused into thinking that a dynamic call that occurred once but was
/// randomly included in the sample is relevant.
num _minCount = 2;
/// Cache mapping from raw stack frames to source mapped stack frames to
/// speedup lookup of source map frames when running the profiler.
/// The number of source map entries looked up makes caching more important
/// in this case than for typical source map use cases.
Map<String, String> _frameMappingCache = Map();
List<List<Object>> getDynamicStats() {
// Process the accumulated method stats. This may be quite slow as processing
// stack traces is expensive. If there are performance blockers, we should
// switch to a sampling approach that caps the number of _callMethodRecords
// and uses random sampling to decide whether to add each additional record
// to the sample. Main change required is that we need to still show the total
// raw number of dynamic calls so that the magnitude of the dynamic call
// performance hit is clear to users.
Map<String, _MethodStats> callMethodStats = Map();
if (_callMethodRecords.length > 0) {
// Ratio between total record count and sampled records count.
var recordRatio = _totalCallRecords / _callMethodRecords.length;
for (var record in _callMethodRecords) {
String stackStr = JS<String>('!', '#.stack', record.jsError);
var frames = stackStr.split('\n');
// Skip first two lines as the first couple frames are from the dart
// runtime.
var src = frames
.skip(2)
.map((f) =>
_frameMappingCache.putIfAbsent(f, () => stackTraceMapper('\n$f')))
.firstWhere((f) => !f.startsWith('dart:'), orElse: () => '');
var actualTypeName = dart.typeName(record.type);
callMethodStats
.putIfAbsent(
"$actualTypeName <$src>", () => _MethodStats(actualTypeName, src))
.count += recordRatio;
}
// filter out all calls that did not occur at least _minCount times in the
// random sample if we are dealing with a random sample instead of a
// complete profile.
if (_totalCallRecords != _callMethodRecords.length) {
for (var k in callMethodStats.keys.toList()) {
var stats = callMethodStats[k];
var threshold = _minCount * recordRatio;
if (stats.count + 0.001 < threshold) {
callMethodStats.remove(k);
}
}
}
}
_callMethodRecords.clear();
_totalCallRecords = 0;
var keys = callMethodStats.keys.toList();
keys.sort(
(a, b) => callMethodStats[b].count.compareTo(callMethodStats[a].count));
List<List<Object>> ret = [];
for (var key in keys) {
var stats = callMethodStats[key];
ret.add([stats.typeName, stats.frame, stats.count.round()]);
}
return ret;
}
clearDynamicStats() {
_callMethodRecords.clear();
}
// We need to set this property while the sdk is only partially initialized
// so we cannot use a regular Dart field.
bool get _trackProfile => JS<bool>('!', 'dart.__trackProfile');
trackCall(obj) {
if (JS<bool>('!', '!#', _trackProfile)) return;
int index = -1;
_totalCallRecords++;
if (_callMethodRecords.length == _callRecordSampleSize) {
// Ensure that each sample has an equal
// _callRecordSampleSize / _totalCallRecords chance of inclusion
// by choosing to include the new record in the sample the with the
// appropriate probability randomly evicting one of the existing records.
// Unfortunately we can't use the excellent Random.nextInt method defined
// by Dart from within this library.
index = JS<int>('!', 'Math.floor(Math.random() * #)', _totalCallRecords);
if (index >= _callMethodRecords.length) return; // don't sample
}
var record =
_CallMethodRecord(JS('', 'new Error()'), dart.getReifiedType(obj));
if (index == -1) {
_callMethodRecords.add(record);
} else {
_callMethodRecords[index] = record;
}
}

View file

@ -0,0 +1,283 @@
// 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.
part of dart._js_helper;
// Helper method used by internal libraries.
regExpGetNative(JSSyntaxRegExp regexp) => regexp._nativeRegExp;
/**
* Returns a native version of the RegExp with the global flag set.
*
* The RegExp's `lastIndex` property is zero when it is returned.
*
* The returned regexp is shared, and its `lastIndex` property may be
* modified by other uses, so the returned regexp must be used immediately
* when it's returned, with no user-provided code run in between.
*/
regExpGetGlobalNative(JSSyntaxRegExp regexp) {
var nativeRegexp = regexp._nativeGlobalVersion;
JS("void", "#.lastIndex = 0", nativeRegexp);
return nativeRegexp;
}
/**
* Computes the number of captures in a regexp.
*
* This currently involves creating a new RegExp object with a different
* source and running it against the empty string (the last part is usually
* fast).
*
* The JSSyntaxRegExp could cache the result, and set the cache any time
* it finds a match.
*/
int regExpCaptureCount(JSSyntaxRegExp regexp) {
var nativeAnchoredRegExp = regexp._nativeAnchoredVersion;
JSExtendableArray match =
JS('JSExtendableArray', "#.exec('')", nativeAnchoredRegExp);
// The native-anchored regexp always have one capture more than the original,
// and always matches the empty string.
return match.length - 2;
}
class JSSyntaxRegExp implements RegExp {
final String pattern;
final _nativeRegExp;
var _nativeGlobalRegExp;
var _nativeAnchoredRegExp;
String toString() =>
'RegExp/$pattern/' + JS<String>('!', '#.flags', _nativeRegExp);
JSSyntaxRegExp(String source,
{bool multiLine = false,
bool caseSensitive = true,
bool unicode = false,
bool dotAll = false})
: this.pattern = source,
this._nativeRegExp = makeNative(
source, multiLine, caseSensitive, unicode, dotAll, false);
get _nativeGlobalVersion {
if (_nativeGlobalRegExp != null) return _nativeGlobalRegExp;
return _nativeGlobalRegExp = makeNative(
pattern, _isMultiLine, _isCaseSensitive, _isUnicode, _isDotAll, true);
}
get _nativeAnchoredVersion {
if (_nativeAnchoredRegExp != null) return _nativeAnchoredRegExp;
// An "anchored version" of a regexp is created by adding "|()" to the
// source. This means that the regexp always matches at the first position
// that it tries, and you can see if the original regexp matched, or it
// was the added zero-width match that matched, by looking at the last
// capture. If it is a String, the match participated, otherwise it didn't.
return _nativeAnchoredRegExp = makeNative("$pattern|()", _isMultiLine,
_isCaseSensitive, _isUnicode, _isDotAll, true);
}
bool get _isMultiLine => JS("bool", "#.multiline", _nativeRegExp);
bool get _isCaseSensitive => JS("bool", "!#.ignoreCase", _nativeRegExp);
bool get _isUnicode => JS("bool", "#.unicode", _nativeRegExp);
bool get _isDotAll => JS("bool", "#.dotAll", _nativeRegExp);
static makeNative(@nullCheck String source, bool multiLine,
bool caseSensitive, bool unicode, bool dotAll, bool global) {
String m = multiLine ? 'm' : '';
String i = caseSensitive ? '' : 'i';
String u = unicode ? 'u' : '';
String s = dotAll ? 's' : '';
String g = global ? 'g' : '';
// We're using the JavaScript's try catch instead of the Dart one
// to avoid dragging in Dart runtime support just because of using
// RegExp.
var regexp = JS(
'',
'(function() {'
'try {'
'return new RegExp(#, # + # + # + # + #);'
'} catch (e) {'
'return e;'
'}'
'})()',
source,
m,
i,
u,
s,
g);
if (JS<bool>('!', '# instanceof RegExp', regexp)) return regexp;
// The returned value is the JavaScript exception. Turn it into a
// Dart exception.
String errorMessage = JS<String>('!', r'String(#)', regexp);
throw FormatException("Illegal RegExp pattern: $source, $errorMessage");
}
RegExpMatch firstMatch(@nullCheck String string) {
List m = JS('JSExtendableArray|Null', r'#.exec(#)', _nativeRegExp, string);
if (m == null) return null;
return _MatchImplementation(this, JSArray<String>.of(m));
}
@notNull
bool hasMatch(@nullCheck String string) {
return JS<bool>('!', r'#.test(#)', _nativeRegExp, string);
}
String stringMatch(String string) {
var match = firstMatch(string);
if (match != null) return match.group(0);
return null;
}
Iterable<RegExpMatch> allMatches(@nullCheck String string,
[@nullCheck int start = 0]) {
if (start < 0 || start > string.length) {
throw RangeError.range(start, 0, string.length);
}
return _AllMatchesIterable(this, string, start);
}
RegExpMatch _execGlobal(String string, int start) {
Object regexp = _nativeGlobalVersion;
JS("void", "#.lastIndex = #", regexp, start);
List match = JS("JSExtendableArray|Null", "#.exec(#)", regexp, string);
if (match == null) return null;
return _MatchImplementation(this, JSArray<String>.of(match));
}
RegExpMatch _execAnchored(String string, int start) {
Object regexp = _nativeAnchoredVersion;
JS("void", "#.lastIndex = #", regexp, start);
List match = JS("JSExtendableArray|Null", "#.exec(#)", regexp, string);
if (match == null) return null;
// If the last capture group participated, the original regexp did not
// match at the start position.
if (match[match.length - 1] != null) return null;
match.length -= 1;
return _MatchImplementation(this, JSArray<String>.of(match));
}
RegExpMatch matchAsPrefix(String string, [int start = 0]) {
if (start < 0 || start > string.length) {
throw RangeError.range(start, 0, string.length);
}
return _execAnchored(string, start);
}
bool get isMultiLine => _isMultiLine;
bool get isCaseSensitive => _isCaseSensitive;
bool get isUnicode => _isUnicode;
bool get isDotAll => _isDotAll;
}
class _MatchImplementation implements RegExpMatch {
final Pattern pattern;
// Contains a JS RegExp match object.
// It is an Array of String values with extra "index" and "input" properties.
final List<String> _match;
_MatchImplementation(this.pattern, this._match) {
assert(JS("var", "#.input", _match) is String);
assert(JS("var", "#.index", _match) is int);
}
String get input => JS("String", "#.input", _match);
int get start => JS("int", "#.index", _match);
int get end => start + _match[0].length;
String group(int index) => _match[index];
String operator [](int index) => group(index);
int get groupCount => _match.length - 1;
List<String> groups(List<int> groups) {
List<String> out = [];
for (int i in groups) {
out.add(group(i));
}
return out;
}
String namedGroup(String name) {
var groups = JS('Object', '#.groups', _match);
if (groups != null) {
var result = JS('String|Null', '#[#]', groups, name);
if (result != null || JS<bool>('!', '# in #', name, groups)) {
return result;
}
}
throw ArgumentError.value(name, "name", "Not a capture group name");
}
Iterable<String> get groupNames {
var groups = JS('Object', '#.groups', _match);
if (groups != null) {
var keys = JSArray<String>.of(JS('', 'Object.keys(#)', groups));
return SubListIterable(keys, 0, null);
}
return Iterable.empty();
}
}
class _AllMatchesIterable extends IterableBase<RegExpMatch> {
final JSSyntaxRegExp _re;
final String _string;
final int _start;
_AllMatchesIterable(this._re, this._string, this._start);
Iterator<RegExpMatch> get iterator =>
_AllMatchesIterator(_re, _string, _start);
}
class _AllMatchesIterator implements Iterator<RegExpMatch> {
final JSSyntaxRegExp _regExp;
String _string;
int _nextIndex;
RegExpMatch _current;
_AllMatchesIterator(this._regExp, this._string, this._nextIndex);
RegExpMatch get current => _current;
static bool _isLeadSurrogate(int c) {
return c >= 0xd800 && c <= 0xdbff;
}
static bool _isTrailSurrogate(int c) {
return c >= 0xdc00 && c <= 0xdfff;
}
bool moveNext() {
if (_string == null) return false;
if (_nextIndex <= _string.length) {
var match = _regExp._execGlobal(_string, _nextIndex);
if (match != null) {
_current = match;
int nextIndex = match.end;
if (match.start == nextIndex) {
// Zero-width match. Advance by one more, unless the regexp
// is in unicode mode and it would put us within a surrogate
// pair. In that case, advance past the code point as a whole.
if (_regExp.isUnicode &&
_nextIndex + 1 < _string.length &&
_isLeadSurrogate(_string.codeUnitAt(_nextIndex)) &&
_isTrailSurrogate(_string.codeUnitAt(_nextIndex + 1))) {
nextIndex++;
}
nextIndex++;
}
_nextIndex = nextIndex;
return true;
}
}
_current = null;
_string = null; // Marks iteration as ended.
return false;
}
}
/** Find the first match of [regExp] in [string] at or after [start]. */
RegExpMatch firstMatchAfter(JSSyntaxRegExp regExp, String string, int start) {
return regExp._execGlobal(string, start);
}

View file

@ -0,0 +1,297 @@
// 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.
part of dart._js_helper;
@notNull
int stringIndexOfStringUnchecked(receiver, other, startIndex) {
return JS<int>('!', '#.indexOf(#, #)', receiver, other, startIndex);
}
@notNull
String substring1Unchecked(receiver, startIndex) {
return JS('!', '#.substring(#)', receiver, startIndex);
}
@notNull
String substring2Unchecked(receiver, startIndex, endIndex) {
return JS('!', '#.substring(#, #)', receiver, startIndex, endIndex);
}
@notNull
bool stringContainsStringUnchecked(receiver, other, startIndex) {
return stringIndexOfStringUnchecked(receiver, other, startIndex) >= 0;
}
class StringMatch implements Match {
const StringMatch(int this.start, String this.input, String this.pattern);
int get end => start + pattern.length;
String operator [](int g) => group(g);
int get groupCount => 0;
String group(int group_) {
if (group_ != 0) {
throw RangeError.value(group_);
}
return pattern;
}
List<String> groups(List<int> groups_) {
List<String> result = List<String>();
for (int g in groups_) {
result.add(group(g));
}
return result;
}
final int start;
final String input;
final String pattern;
}
Iterable<Match> allMatchesInStringUnchecked(
String pattern, String string, int startIndex) {
return _StringAllMatchesIterable(string, pattern, startIndex);
}
class _StringAllMatchesIterable extends Iterable<Match> {
final String _input;
final String _pattern;
final int _index;
_StringAllMatchesIterable(this._input, this._pattern, this._index);
Iterator<Match> get iterator =>
_StringAllMatchesIterator(_input, _pattern, _index);
Match get first {
int index = stringIndexOfStringUnchecked(_input, _pattern, _index);
if (index >= 0) {
return StringMatch(index, _input, _pattern);
}
throw IterableElementError.noElement();
}
}
class _StringAllMatchesIterator implements Iterator<Match> {
final String _input;
final String _pattern;
int _index;
Match _current;
_StringAllMatchesIterator(this._input, this._pattern, this._index);
bool moveNext() {
if (_index + _pattern.length > _input.length) {
_current = null;
return false;
}
var index = stringIndexOfStringUnchecked(_input, _pattern, _index);
if (index < 0) {
_index = _input.length + 1;
_current = null;
return false;
}
int end = index + _pattern.length;
_current = StringMatch(index, _input, _pattern);
// Empty match, don't start at same location again.
if (end == _index) end++;
_index = end;
return true;
}
Match get current => _current;
}
@notNull
bool stringContainsUnchecked(
@notNull String receiver, @notNull other, int startIndex) {
if (other is String) {
return stringContainsStringUnchecked(receiver, other, startIndex);
} else if (other is JSSyntaxRegExp) {
return other.hasMatch(receiver.substring(startIndex));
} else {
var substr = receiver.substring(startIndex);
return other.allMatches(substr).isNotEmpty;
}
}
@notNull
String stringReplaceJS(String receiver, replacer, String replacement) {
// The JavaScript String.replace method recognizes replacement
// patterns in the replacement string. Dart does not have that
// behavior.
replacement = JS<String>('!', r'#.replace(/\$/g, "$$$$")', replacement);
return JS<String>('!', r'#.replace(#, #)', receiver, replacer, replacement);
}
@notNull
String stringReplaceFirstRE(@notNull String receiver, JSSyntaxRegExp regexp,
String replacement, int startIndex) {
var match = regexp._execGlobal(receiver, startIndex);
if (match == null) return receiver;
var start = match.start;
var end = match.end;
return stringReplaceRangeUnchecked(receiver, start, end, replacement);
}
/// Returns a string for a RegExp pattern that matches [string]. This is done by
/// escaping all RegExp metacharacters.
@notNull
String quoteStringForRegExp(string) {
return JS<String>('!', r'#.replace(/[[\]{}()*+?.\\^$|]/g, "\\$&")', string);
}
@notNull
String stringReplaceAllUnchecked(@notNull String receiver,
@nullCheck Pattern pattern, @nullCheck String replacement) {
if (pattern is String) {
if (pattern == "") {
if (receiver == "") {
return replacement;
} else {
StringBuffer result = StringBuffer();
int length = receiver.length;
result.write(replacement);
for (int i = 0; i < length; i++) {
result.write(receiver[i]);
result.write(replacement);
}
return result.toString();
}
} else {
return JS<String>(
'!', '#.split(#).join(#)', receiver, pattern, replacement);
}
} else if (pattern is JSSyntaxRegExp) {
var re = regExpGetGlobalNative(pattern);
return stringReplaceJS(receiver, re, replacement);
} else {
// TODO(floitsch): implement generic String.replace (with patterns).
throw "String.replaceAll(Pattern) UNIMPLEMENTED";
}
}
String _matchString(Match match) => match[0];
String _stringIdentity(String string) => string;
@notNull
String stringReplaceAllFuncUnchecked(
String receiver,
@nullCheck Pattern pattern,
String onMatch(Match match),
String onNonMatch(String nonMatch)) {
if (onMatch == null) onMatch = _matchString;
if (onNonMatch == null) onNonMatch = _stringIdentity;
if (pattern is String) {
return stringReplaceAllStringFuncUnchecked(
receiver, pattern, onMatch, onNonMatch);
}
StringBuffer buffer = StringBuffer();
int startIndex = 0;
for (Match match in pattern.allMatches(receiver)) {
buffer.write(onNonMatch(receiver.substring(startIndex, match.start)));
buffer.write(onMatch(match));
startIndex = match.end;
}
buffer.write(onNonMatch(receiver.substring(startIndex)));
return buffer.toString();
}
@notNull
String stringReplaceAllEmptyFuncUnchecked(String receiver,
String onMatch(Match match), String onNonMatch(String nonMatch)) {
// Pattern is the empty string.
StringBuffer buffer = StringBuffer();
int length = receiver.length;
int i = 0;
buffer.write(onNonMatch(""));
while (i < length) {
buffer.write(onMatch(StringMatch(i, receiver, "")));
// Special case to avoid splitting a surrogate pair.
int code = receiver.codeUnitAt(i);
if ((code & ~0x3FF) == 0xD800 && length > i + 1) {
// Leading surrogate;
code = receiver.codeUnitAt(i + 1);
if ((code & ~0x3FF) == 0xDC00) {
// Matching trailing surrogate.
buffer.write(onNonMatch(receiver.substring(i, i + 2)));
i += 2;
continue;
}
}
buffer.write(onNonMatch(receiver[i]));
i++;
}
buffer.write(onMatch(StringMatch(i, receiver, "")));
buffer.write(onNonMatch(""));
return buffer.toString();
}
@notNull
String stringReplaceAllStringFuncUnchecked(String receiver, String pattern,
String onMatch(Match match), String onNonMatch(String nonMatch)) {
int patternLength = pattern.length;
if (patternLength == 0) {
return stringReplaceAllEmptyFuncUnchecked(receiver, onMatch, onNonMatch);
}
int length = receiver.length;
StringBuffer buffer = StringBuffer();
int startIndex = 0;
while (startIndex < length) {
int position = stringIndexOfStringUnchecked(receiver, pattern, startIndex);
if (position == -1) {
break;
}
buffer.write(onNonMatch(receiver.substring(startIndex, position)));
buffer.write(onMatch(StringMatch(position, receiver, pattern)));
startIndex = position + patternLength;
}
buffer.write(onNonMatch(receiver.substring(startIndex)));
return buffer.toString();
}
@notNull
String stringReplaceFirstUnchecked(@notNull String receiver,
@nullCheck Pattern pattern, String replacement, int startIndex) {
if (pattern is String) {
int index = stringIndexOfStringUnchecked(receiver, pattern, startIndex);
if (index < 0) return receiver;
int end = index + pattern.length;
return stringReplaceRangeUnchecked(receiver, index, end, replacement);
}
if (pattern is JSSyntaxRegExp) {
return startIndex == 0
? stringReplaceJS(receiver, regExpGetNative(pattern), replacement)
: stringReplaceFirstRE(receiver, pattern, replacement, startIndex);
}
Iterator<Match> matches = pattern.allMatches(receiver, startIndex).iterator;
if (!matches.moveNext()) return receiver;
Match match = matches.current;
return receiver.replaceRange(match.start, match.end, replacement);
}
@notNull
String stringReplaceFirstMappedUnchecked(String receiver, Pattern pattern,
String replace(Match current), int startIndex) {
Iterator<Match> matches = pattern.allMatches(receiver, startIndex).iterator;
if (!matches.moveNext()) return receiver;
Match match = matches.current;
String replacement = "${replace(match)}";
return receiver.replaceRange(match.start, match.end, replacement);
}
@notNull
String stringJoinUnchecked(array, separator) {
return JS<String>('!', r'#.join(#)', array, separator);
}
@notNull
String stringReplaceRangeUnchecked(
String receiver, int start, int end, String replacement) {
String prefix = JS('!', '#.substring(0, #)', receiver, start);
String suffix = JS('!', '#.substring(#)', receiver, end);
return "$prefix$replacement$suffix";
}

View file

@ -0,0 +1,2 @@
# Generated by pub on 2015-12-07 17:08:11.724.
js_runtime:lib/

View file

@ -0,0 +1,18 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of _js_helper;
/// Marks a class as native and defines its JavaScript name(s).
class Native {
final String name;
const Native(this.name);
}
class _Patch {
const _Patch();
}
/// Annotation that marks the declaration as a patch.
const _Patch patch = const _Patch();

View file

@ -0,0 +1,694 @@
// 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 file for the dart:async library.
import 'dart:_js_helper'
show
patch,
ExceptionAndStackTrace,
convertDartClosureToJS,
getTraceFromException,
requiresPreamble,
wrapException,
unwrapException;
import 'dart:_foreign_helper' show JS, JS_GET_FLAG;
import 'dart:_async_await_error_codes' as async_error_codes;
import "dart:collection" show IterableBase;
@patch
class _AsyncRun {
@patch
static void _scheduleImmediate(void callback()) {
_scheduleImmediateClosure(callback);
}
// Lazily initialized.
static final Function _scheduleImmediateClosure =
_initializeScheduleImmediate();
static Function _initializeScheduleImmediate() {
requiresPreamble();
if (JS('', 'self.scheduleImmediate') != null) {
return _scheduleImmediateJsOverride;
}
if (JS('', 'self.MutationObserver') != null &&
JS('', 'self.document') != null) {
// Use mutationObservers.
var div = JS('', 'self.document.createElement("div")');
var span = JS('', 'self.document.createElement("span")');
var storedCallback;
internalCallback(_) {
var f = storedCallback;
storedCallback = null;
f();
}
var observer = JS('', 'new self.MutationObserver(#)',
convertDartClosureToJS(internalCallback, 1));
JS('', '#.observe(#, { childList: true })', observer, div);
return (void callback()) {
assert(storedCallback == null);
storedCallback = callback;
// Because of a broken shadow-dom polyfill we have to change the
// children instead a cheap property.
JS('', '#.firstChild ? #.removeChild(#): #.appendChild(#)', div, div,
span, div, span);
};
} else if (JS('', 'self.setImmediate') != null) {
return _scheduleImmediateWithSetImmediate;
}
// TODO(20055): We should use DOM promises when available.
return _scheduleImmediateWithTimer;
}
static void _scheduleImmediateJsOverride(void callback()) {
internalCallback() {
callback();
}
JS('void', 'self.scheduleImmediate(#)',
convertDartClosureToJS(internalCallback, 0));
}
static void _scheduleImmediateWithSetImmediate(void callback()) {
internalCallback() {
callback();
}
JS('void', 'self.setImmediate(#)',
convertDartClosureToJS(internalCallback, 0));
}
static void _scheduleImmediateWithTimer(void callback()) {
Timer._createTimer(Duration.zero, callback);
}
}
@patch
class DeferredLibrary {
@patch
Future<Null> load() {
throw 'DeferredLibrary not supported. '
'please use the `import "lib.dart" deferred as lib` syntax.';
}
}
@patch
class Timer {
@patch
static Timer _createTimer(Duration duration, void callback()) {
int milliseconds = duration.inMilliseconds;
if (milliseconds < 0) milliseconds = 0;
return new _TimerImpl(milliseconds, callback);
}
@patch
static Timer _createPeriodicTimer(
Duration duration, void callback(Timer timer)) {
int milliseconds = duration.inMilliseconds;
if (milliseconds < 0) milliseconds = 0;
return new _TimerImpl.periodic(milliseconds, callback);
}
}
class _TimerImpl implements Timer {
final bool _once;
int _handle;
int _tick = 0;
_TimerImpl(int milliseconds, void callback()) : _once = true {
if (_hasTimer()) {
void internalCallback() {
_handle = null;
this._tick = 1;
callback();
}
_handle = JS('int', 'self.setTimeout(#, #)',
convertDartClosureToJS(internalCallback, 0), milliseconds);
} else {
throw new UnsupportedError('`setTimeout()` not found.');
}
}
_TimerImpl.periodic(int milliseconds, void callback(Timer timer))
: _once = false {
if (_hasTimer()) {
int start = JS('int', 'Date.now()');
_handle = JS(
'int',
'self.setInterval(#, #)',
convertDartClosureToJS(() {
int tick = this._tick + 1;
if (milliseconds > 0) {
int duration = JS('int', 'Date.now()') - start;
if (duration > (tick + 1) * milliseconds) {
tick = duration ~/ milliseconds;
}
}
this._tick = tick;
callback(this);
}, 0),
milliseconds);
} else {
throw new UnsupportedError('Periodic timer.');
}
}
@override
bool get isActive => _handle != null;
@override
int get tick => _tick;
@override
void cancel() {
if (_hasTimer()) {
if (_handle == null) return;
if (_once) {
JS('void', 'self.clearTimeout(#)', _handle);
} else {
JS('void', 'self.clearInterval(#)', _handle);
}
_handle = null;
} else {
throw new UnsupportedError('Canceling a timer.');
}
}
}
bool _hasTimer() {
requiresPreamble();
return JS('', 'self.setTimeout') != null;
}
class _AsyncAwaitCompleter<T> implements Completer<T> {
final _future = new _Future<T>();
bool isSync;
_AsyncAwaitCompleter() : isSync = false;
void complete([FutureOr<T> value]) {
if (!isSync || value is Future<T>) {
_future._asyncComplete(value);
} else {
_future._completeWithValue(value);
}
}
void completeError(e, [st]) {
if (isSync) {
_future._completeError(e, st);
} else {
_future._asyncCompleteError(e, st);
}
}
Future<T> get future => _future;
bool get isCompleted => !_future._mayComplete;
}
/// Creates a Completer for an `async` function.
///
/// Used as part of the runtime support for the async/await transformation.
Completer<T> _makeAsyncAwaitCompleter<T>() {
return new _AsyncAwaitCompleter<T>();
}
/// Initiates the computation of an `async` function and starts the body
/// synchronously.
///
/// Used as part of the runtime support for the async/await transformation.
///
/// This function sets up the first call into the transformed [bodyFunction].
/// Independently, it takes the [completer] and returns the future of the
/// completer for convenience of the transformed code.
dynamic _asyncStartSync(
_WrappedAsyncBody bodyFunction, _AsyncAwaitCompleter completer) {
bodyFunction(async_error_codes.SUCCESS, null);
completer.isSync = true;
return completer.future;
}
/// Performs the `await` operation of an `async` function.
///
/// Used as part of the runtime support for the async/await transformation.
///
/// Arranges for [bodyFunction] to be called when the future or value [object]
/// is completed with a code [async_error_codes.SUCCESS] or
/// [async_error_codes.ERROR] depending on the success of the future.
dynamic _asyncAwait(dynamic object, _WrappedAsyncBody bodyFunction) {
_awaitOnObject(object, bodyFunction);
}
/// Completes the future of an `async` function.
///
/// Used as part of the runtime support for the async/await transformation.
///
/// This function is used when the `async` function returns (explicitly or
/// implicitly).
dynamic _asyncReturn(dynamic object, Completer completer) {
completer.complete(object);
}
/// Completes the future of an `async` function with an error.
///
/// Used as part of the runtime support for the async/await transformation.
///
/// This function is used when the `async` function re-throws an exception.
dynamic _asyncRethrow(dynamic object, Completer completer) {
// The error is a js-error.
completer.completeError(
unwrapException(object), getTraceFromException(object));
}
/// Awaits on the given [object].
///
/// If the [object] is a Future, registers on it, otherwise wraps it into a
/// future first.
///
/// The [bodyFunction] argument is the continuation that should be invoked
/// when the future completes.
void _awaitOnObject(object, _WrappedAsyncBody bodyFunction) {
Function thenCallback =
(result) => bodyFunction(async_error_codes.SUCCESS, result);
Function errorCallback = (dynamic error, StackTrace stackTrace) {
ExceptionAndStackTrace wrappedException =
new ExceptionAndStackTrace(error, stackTrace);
bodyFunction(async_error_codes.ERROR, wrappedException);
};
if (object is _Future) {
// We can skip the zone registration, since the bodyFunction is already
// registered (see [_wrapJsFunctionForAsync]).
object._thenAwait(thenCallback, errorCallback);
} else if (object is Future) {
object.then(thenCallback, onError: errorCallback);
} else {
_Future future = new _Future().._setValue(object);
// We can skip the zone registration, since the bodyFunction is already
// registered (see [_wrapJsFunctionForAsync]).
future._thenAwait(thenCallback, null);
}
}
typedef void _WrappedAsyncBody(int errorCode, dynamic result);
_WrappedAsyncBody _wrapJsFunctionForAsync(dynamic /* js function */ function) {
var protected = JS(
'',
"""
(function (fn, ERROR) {
// Invokes [function] with [errorCode] and [result].
//
// If (and as long as) the invocation throws, calls [function] again,
// with an error-code.
return function(errorCode, result) {
while (true) {
try {
fn(errorCode, result);
break;
} catch (error) {
result = error;
errorCode = ERROR;
}
}
}
})(#, #)""",
function,
async_error_codes.ERROR);
return Zone.current.registerBinaryCallback((int errorCode, dynamic result) {
JS('', '#(#, #)', protected, errorCode, result);
});
}
/// Implements the runtime support for async* functions.
///
/// Called by the transformed function for each original return, await, yield,
/// yield* and before starting the function.
///
/// When the async* function wants to return it calls this function with
/// [asyncBody] == [async_error_codes.SUCCESS], the asyncStarHelper takes this
/// as signal to close the stream.
///
/// When the async* function wants to signal that an uncaught error was thrown,
/// it calls this function with [asyncBody] == [async_error_codes.ERROR],
/// the streamHelper takes this as signal to addError [object] to the
/// [controller] and close it.
///
/// If the async* function wants to do a yield or yield*, it calls this function
/// with [object] being an [IterationMarker].
///
/// In the case of a yield or yield*, if the stream subscription has been
/// canceled, schedules [asyncBody] to be called with
/// [async_error_codes.STREAM_WAS_CANCELED].
///
/// If [object] is a single-yield [IterationMarker], adds the value of the
/// [IterationMarker] to the stream. If the stream subscription has been
/// paused, return early. Otherwise schedule the helper function to be
/// executed again.
///
/// If [object] is a yield-star [IterationMarker], starts listening to the
/// yielded stream, and adds all events and errors to our own controller (taking
/// care if the subscription has been paused or canceled) - when the sub-stream
/// is done, schedules [asyncBody] again.
///
/// If the async* function wants to do an await it calls this function with
/// [object] not an [IterationMarker].
///
/// If [object] is not a [Future], it is wrapped in a `Future.value`.
/// The [asyncBody] is called on completion of the future (see [asyncHelper].
void _asyncStarHelper(
dynamic object,
dynamic /* int | _WrappedAsyncBody */ bodyFunctionOrErrorCode,
_AsyncStarStreamController controller) {
if (identical(bodyFunctionOrErrorCode, async_error_codes.SUCCESS)) {
// This happens on return from the async* function.
if (controller.isCanceled) {
controller.cancelationFuture._completeWithValue(null);
} else {
controller.close();
}
return;
} else if (identical(bodyFunctionOrErrorCode, async_error_codes.ERROR)) {
// The error is a js-error.
if (controller.isCanceled) {
controller.cancelationFuture._completeError(
unwrapException(object), getTraceFromException(object));
} else {
controller.addError(
unwrapException(object), getTraceFromException(object));
controller.close();
}
return;
}
if (object is _IterationMarker) {
if (controller.isCanceled) {
bodyFunctionOrErrorCode(async_error_codes.STREAM_WAS_CANCELED, null);
return;
}
if (object.state == _IterationMarker.YIELD_SINGLE) {
controller.add(object.value);
scheduleMicrotask(() {
if (controller.isPaused) {
// We only suspend the thread inside the microtask in order to allow
// listeners on the output stream to pause in response to the just
// output value, and have the stream immediately stop producing.
controller.isSuspended = true;
return;
}
bodyFunctionOrErrorCode(null, async_error_codes.SUCCESS);
});
return;
} else if (object.state == _IterationMarker.YIELD_STAR) {
Stream stream = object.value;
// Errors of [stream] are passed though to the main stream. (see
// [AsyncStreamController.addStream]).
// TODO(sigurdm): The spec is not very clear here. Clarify with Gilad.
controller.addStream(stream).then((_) {
// No check for isPaused here because the spec 17.16.2 only
// demands checks *before* each element in [stream] not after the last
// one. On the other hand we check for isCanceled, as that check happens
// after insertion of each element.
int errorCode = controller.isCanceled
? async_error_codes.STREAM_WAS_CANCELED
: async_error_codes.SUCCESS;
bodyFunctionOrErrorCode(errorCode, null);
});
return;
}
}
_awaitOnObject(object, bodyFunctionOrErrorCode);
}
Stream _streamOfController(_AsyncStarStreamController controller) {
return controller.stream;
}
/// A wrapper around a [StreamController] that keeps track of the state of
/// the execution of an async* function.
/// It can be in 1 of 3 states:
///
/// - running/scheduled
/// - suspended
/// - canceled
///
/// If yielding while the subscription is paused it will become suspended. And
/// only resume after the subscription is resumed or canceled.
class _AsyncStarStreamController<T> {
StreamController<T> controller;
Stream get stream => controller.stream;
/// True when the async* function has yielded while being paused.
/// When true execution will only resume after a `onResume` or `onCancel`
/// event.
bool isSuspended = false;
bool get isPaused => controller.isPaused;
_Future cancelationFuture = null;
/// True after the StreamSubscription has been cancelled.
/// When this is true, errors thrown from the async* body should go to the
/// [cancelationFuture] instead of adding them to [controller], and
/// returning from the async function should complete [cancelationFuture].
bool get isCanceled => cancelationFuture != null;
add(event) => controller.add(event);
addStream(Stream<T> stream) {
return controller.addStream(stream, cancelOnError: false);
}
addError(error, stackTrace) => controller.addError(error, stackTrace);
close() => controller.close();
_AsyncStarStreamController(_WrappedAsyncBody body) {
_resumeBody() {
scheduleMicrotask(() {
body(async_error_codes.SUCCESS, null);
});
}
controller = new StreamController<T>(onListen: () {
_resumeBody();
}, onResume: () {
// Only schedule again if the async* function actually is suspended.
// Resume directly instead of scheduling, so that the sequence
// `pause-resume-pause` will result in one extra event produced.
if (isSuspended) {
isSuspended = false;
_resumeBody();
}
}, onCancel: () {
// If the async* is finished we ignore cancel events.
if (!controller.isClosed) {
cancelationFuture = new _Future();
if (isSuspended) {
// Resume the suspended async* function to run finalizers.
isSuspended = false;
scheduleMicrotask(() {
body(async_error_codes.STREAM_WAS_CANCELED, null);
});
}
return cancelationFuture;
}
});
}
}
/// Creates a stream controller for an `async*` function.
///
/// Used as part of the runtime support for the async/await transformation.
_makeAsyncStarStreamController<T>(_WrappedAsyncBody body) {
return new _AsyncStarStreamController<T>(body);
}
class _IterationMarker {
static const YIELD_SINGLE = 0;
static const YIELD_STAR = 1;
static const ITERATION_ENDED = 2;
static const UNCAUGHT_ERROR = 3;
final value;
final int state;
const _IterationMarker._(this.state, this.value);
static yieldStar(dynamic /* Iterable or Stream */ values) {
return new _IterationMarker._(YIELD_STAR, values);
}
static endOfIteration() {
return const _IterationMarker._(ITERATION_ENDED, null);
}
static yieldSingle(dynamic value) {
return new _IterationMarker._(YIELD_SINGLE, value);
}
static uncaughtError(dynamic error) {
return new _IterationMarker._(UNCAUGHT_ERROR, error);
}
toString() => "IterationMarker($state, $value)";
}
class _SyncStarIterator<T> implements Iterator<T> {
// _SyncStarIterator handles stepping a sync* generator body state machine.
//
// It also handles the stepping over 'nested' iterators to flatten yield*
// statements. For non-sync* iterators, [_nestedIterator] contains the
// iterator. We delegate to [_nestedIterator] when it is not `null`.
//
// For nested sync* iterators, [this] iterator acts on behalf of the innermost
// nested sync* iterator. The current state machine is suspended on a stack
// until the inner state machine ends.
// The state machine for the innermost _SyncStarIterator.
dynamic _body;
// The current value, unless iterating a non-sync* nested iterator.
T _current = null;
// This is the nested iterator when iterating a yield* of a non-sync iterator.
// TODO(32956): In strong-mode, yield* takes an Iterable<T> (possibly checked
// with an implicit downcast), so change type to Iterator<T>.
Iterator _nestedIterator = null;
// Stack of suspended state machines when iterating a yield* of a sync*
// iterator.
List _suspendedBodies = null;
_SyncStarIterator(this._body);
T get current {
if (_nestedIterator == null) return _current;
return _nestedIterator.current;
}
_runBody() {
// TODO(sra): Find a way to hard-wire SUCCESS and ERROR codes.
return JS(
'',
'''
// Invokes [body] with [errorCode] and [result].
//
// If (and as long as) the invocation throws, calls [function] again,
// with an error-code.
(function(body, SUCCESS, ERROR) {
var errorValue, errorCode = SUCCESS;
while (true) {
try {
return body(errorCode, errorValue);
} catch (error) {
errorValue = error;
errorCode = ERROR;
}
}
})(#, #, #)''',
_body,
async_error_codes.SUCCESS,
async_error_codes.ERROR);
}
bool moveNext() {
while (true) {
if (_nestedIterator != null) {
if (_nestedIterator.moveNext()) {
return true;
} else {
_nestedIterator = null;
}
}
var value = _runBody();
if (value is _IterationMarker) {
int state = value.state;
if (state == _IterationMarker.ITERATION_ENDED) {
if (_suspendedBodies == null || _suspendedBodies.isEmpty) {
_current = null;
// Rely on [_body] to repeatedly return `ITERATION_ENDED`.
return false;
}
// Resume the innermost suspended iterator.
_body = _suspendedBodies.removeLast();
continue;
} else if (state == _IterationMarker.UNCAUGHT_ERROR) {
// Rely on [_body] to repeatedly return `UNCAUGHT_ERROR`.
// This is a wrapped exception, so we use JavaScript throw to throw
// it.
JS('', 'throw #', value.value);
} else {
assert(state == _IterationMarker.YIELD_STAR);
Iterator inner = value.value.iterator;
if (inner is _SyncStarIterator) {
// Suspend the current state machine and start acting on behalf of
// the nested state machine.
//
// TODO(sra): Recognize "tail yield*" statements and avoid
// suspending the current body when all it will do is step without
// effect to ITERATION_ENDED.
(_suspendedBodies ??= []).add(_body);
_body = inner._body;
continue;
} else {
_nestedIterator = inner;
// TODO(32956): Change to the following when strong-mode is the only
// option:
//
// _nestedIterator = JS<Iterator<T>>('','#', inner);
continue;
}
}
} else {
// TODO(32956): Remove this test.
_current = JS<T>('', '#', value);
return true;
}
}
return false; // TODO(sra): Fix type inference so that this is not needed.
}
}
/// Creates an Iterable for a `sync*` function.
///
/// Used as part of the runtime support for the async/await transformation.
_SyncStarIterable<T> _makeSyncStarIterable<T>(body) {
return new _SyncStarIterable<T>(body);
}
/// An Iterable corresponding to a sync* method.
///
/// Each invocation of a sync* method will return a new instance of this class.
class _SyncStarIterable<T> extends IterableBase<T> {
// This is a function that will return a helper function that does the
// iteration of the sync*.
//
// Each invocation should give a body with fresh state.
final dynamic /* js function */ _outerHelper;
_SyncStarIterable(this._outerHelper);
Iterator<T> get iterator =>
new _SyncStarIterator<T>(JS('', '#()', _outerHelper));
}
@patch
void _rethrow(Object error, StackTrace stackTrace) {
error = wrapException(error);
JS('void', '#.stack = #', error, stackTrace.toString());
JS('void', 'throw #', error);
}

View file

@ -0,0 +1,10 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:_js_helper' show patch;
@patch
void _waitForEvent(int timeoutMillis) {
throw new UnsupportedError("waitForEvent");
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,222 @@
// 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.
part of _js_helper;
class ConstantMapView<K, V> extends UnmodifiableMapView<K, V>
implements ConstantMap<K, V> {
ConstantMapView(Map<K, V> base) : super(base);
}
abstract class ConstantMap<K, V> implements Map<K, V> {
// Used to create unmodifiable maps from other maps.
factory ConstantMap.from(Map other) {
List keys = new List<K>.from(other.keys);
bool allStrings = true;
for (var k in keys) {
if (k is! String) {
allStrings = false;
break;
}
}
if (allStrings) {
bool containsProto = false;
var protoValue = null;
var object = JS('=Object', '{}');
int length = 0;
for (var k in keys) {
V v = other[k];
if (k != '__proto__') {
if (!jsHasOwnProperty(object, k)) length++;
JS('void', '#[#] = #', object, k, v);
} else {
containsProto = true;
protoValue = v;
}
}
if (containsProto) {
length++;
return new ConstantProtoMap<K, V>._(length, object, keys, protoValue);
}
return new ConstantStringMap<K, V>._(length, object, keys);
}
// TODO(lrn): Make a proper unmodifiable map implementation.
return new ConstantMapView<K, V>(new Map.from(other));
}
const ConstantMap._();
Map<RK, RV> cast<RK, RV>() => Map.castFrom<K, V, RK, RV>(this);
bool get isEmpty => length == 0;
bool get isNotEmpty => !isEmpty;
String toString() => MapBase.mapToString(this);
static Null _throwUnmodifiable() {
throw new UnsupportedError('Cannot modify unmodifiable Map');
}
void operator []=(K key, V val) => _throwUnmodifiable();
V putIfAbsent(K key, V ifAbsent()) => _throwUnmodifiable();
V remove(Object key) => _throwUnmodifiable();
void clear() => _throwUnmodifiable();
void addAll(Map<K, V> other) => _throwUnmodifiable();
Iterable<MapEntry<K, V>> get entries sync* {
for (var key in keys) yield new MapEntry<K, V>(key, this[key]);
}
void addEntries(Iterable<MapEntry<K, V>> entries) {
for (var entry in entries) this[entry.key] = entry.value;
}
Map<K2, V2> map<K2, V2>(MapEntry<K2, V2> transform(K key, V value)) {
var result = <K2, V2>{};
this.forEach((K key, V value) {
var entry = transform(key, value);
result[entry.key] = entry.value;
});
return result;
}
V update(K key, V update(V value), {V ifAbsent()}) {
_throwUnmodifiable();
}
void updateAll(V update(K key, V value)) {
_throwUnmodifiable();
}
void removeWhere(bool test(K key, V value)) {
_throwUnmodifiable();
}
}
class ConstantStringMap<K, V> extends ConstantMap<K, V> {
// This constructor is not used for actual compile-time constants.
// The instantiation of constant maps is shortcut by the compiler.
const ConstantStringMap._(this._length, this._jsObject, this._keys)
: super._();
// TODO(18131): Ensure type inference knows the precise types of the fields.
final int _length;
// A constant map is backed by a JavaScript object.
final _jsObject;
final List<K> _keys;
int get length => JS('JSUInt31', '#', _length);
List<K> get _keysArray => JS('JSUnmodifiableArray', '#', _keys);
bool containsValue(Object needle) {
return values.any((V value) => value == needle);
}
bool containsKey(Object key) {
if (key is! String) return false;
if ('__proto__' == key) return false;
return jsHasOwnProperty(_jsObject, key);
}
V operator [](Object key) {
if (!containsKey(key)) return null;
return JS('', '#', _fetch(key));
}
// [_fetch] is the indexer for keys for which `containsKey(key)` is true.
_fetch(key) => jsPropertyAccess(_jsObject, key);
void forEach(void f(K key, V value)) {
// Use a JS 'cast' to get efficient loop. Type inference doesn't get this
// since constant map representation is chosen after type inference and the
// instantiation is shortcut by the compiler.
var keys = _keysArray;
for (int i = 0; i < keys.length; i++) {
var key = keys[i];
f(key, _fetch(key));
}
}
Iterable<K> get keys {
return new _ConstantMapKeyIterable<K>(this);
}
Iterable<V> get values {
return new MappedIterable<K, V>(_keysArray, (key) => _fetch(key));
}
}
class ConstantProtoMap<K, V> extends ConstantStringMap<K, V> {
// This constructor is not used. The instantiation is shortcut by the
// compiler. It is here to make the uninitialized final fields legal.
ConstantProtoMap._(length, jsObject, keys, this._protoValue)
: super._(length, jsObject, keys);
final V _protoValue;
bool containsKey(Object key) {
if (key is! String) return false;
if ('__proto__' == key) return true;
return jsHasOwnProperty(_jsObject, key);
}
_fetch(key) =>
'__proto__' == key ? _protoValue : jsPropertyAccess(_jsObject, key);
}
class _ConstantMapKeyIterable<K> extends Iterable<K> {
ConstantStringMap<K, dynamic> _map;
_ConstantMapKeyIterable(this._map);
Iterator<K> get iterator => _map._keysArray.iterator;
int get length => _map._keysArray.length;
}
class GeneralConstantMap<K, V> extends ConstantMap<K, V> {
// This constructor is not used. The instantiation is shortcut by the
// compiler. It is here to make the uninitialized final fields legal.
GeneralConstantMap(this._jsData) : super._();
// [_jsData] holds a key-value pair list.
final _jsData;
// We cannot create the backing map on creation since hashCode interceptors
// have not been defined when constants are created.
Map<K, V> _getMap() {
LinkedHashMap<K, V> backingMap = JS('LinkedHashMap|Null', r'#.$map', this);
if (backingMap == null) {
backingMap = new JsLinkedHashMap<K, V>();
fillLiteralMap(_jsData, backingMap);
JS('', r'#.$map = #', this, backingMap);
}
return backingMap;
}
bool containsValue(Object needle) {
return _getMap().containsValue(needle);
}
bool containsKey(Object key) {
return _getMap().containsKey(key);
}
V operator [](Object key) {
return _getMap()[key];
}
void forEach(void f(K key, V value)) {
_getMap().forEach(f);
}
Iterable<K> get keys {
return _getMap().keys;
}
Iterable<V> get values {
return _getMap().values;
}
int get length => _getMap().length;
}

View file

@ -0,0 +1,502 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Patch file for dart:convert library.
import 'dart:_js_helper' show argumentErrorValue, patch;
import 'dart:_foreign_helper' show JS;
import 'dart:_interceptors' show JSArray, JSExtendableArray;
import 'dart:_internal' show MappedIterable, ListIterable;
import 'dart:collection' show LinkedHashMap, MapBase;
import 'dart:_native_typed_data' show NativeUint8List;
/// Parses [json] and builds the corresponding parsed JSON value.
///
/// Parsed JSON values Nare of the types [num], [String], [bool], [Null],
/// [List]s of parsed JSON values or [Map]s from [String] to parsed
/// JSON values.
///
/// The optional [reviver] function, if provided, is called once for each object
/// or list property parsed. The arguments are the property name ([String]) or
/// list index ([int]), and the value is the parsed value. The return value of
/// the reviver will be used as the value of that property instead of the parsed
/// value. The top level value is passed to the reviver with the empty string
/// as a key.
///
/// Throws [FormatException] if the input is not valid JSON text.
@patch
_parseJson(String source, reviver(key, value)) {
if (source is! String) throw argumentErrorValue(source);
var parsed;
try {
parsed = JS('=Object|JSExtendableArray|Null|bool|num|String',
'JSON.parse(#)', source);
} catch (e) {
throw new FormatException(JS('String', 'String(#)', e));
}
if (reviver == null) {
return _convertJsonToDartLazy(parsed);
} else {
return _convertJsonToDart(parsed, reviver);
}
}
/// Walks the raw JavaScript value [json], replacing JavaScript Objects with
/// Maps. [json] is expected to be freshly allocated so elements can be replaced
/// in-place.
_convertJsonToDart(json, reviver(key, value)) {
assert(reviver != null);
walk(e) {
// JavaScript null, string, number, bool are in the correct representation.
if (JS('bool', '# == null', e) || JS('bool', 'typeof # != "object"', e)) {
return e;
}
// This test is needed to avoid identifying '{"__proto__":[]}' as an Array.
// TODO(sra): Replace this test with cheaper '#.constructor === Array' when
// bug 621 below is fixed.
if (JS('bool', 'Object.getPrototypeOf(#) === Array.prototype', e)) {
// In-place update of the elements since JS Array is a Dart List.
for (int i = 0; i < JS('int', '#.length', e); i++) {
// Use JS indexing to avoid range checks. We know this is the only
// reference to the list, but the compiler will likely never be able to
// tell that this instance of the list cannot have its length changed by
// the reviver even though it later will be passed to the reviver at the
// outer level.
var item = JS('', '#[#]', e, i);
JS('', '#[#]=#', e, i, reviver(i, walk(item)));
}
return e;
}
// Otherwise it is a plain object, so copy to a JSON map, so we process
// and revive all entries recursively.
_JsonMap map = new _JsonMap(e);
var processed = map._processed;
List<String> keys = map._computeKeys();
for (int i = 0; i < keys.length; i++) {
String key = keys[i];
var revived = reviver(key, walk(JS('', '#[#]', e, key)));
JS('', '#[#]=#', processed, key, revived);
}
// Update the JSON map structure so future access is cheaper.
map._original = processed; // Don't keep two objects around.
return map;
}
return reviver(null, walk(json));
}
_convertJsonToDartLazy(object) {
// JavaScript null and undefined are represented as null.
if (object == null) return null;
// JavaScript string, number, bool already has the correct representation.
if (JS('bool', 'typeof # != "object"', object)) {
return object;
}
// This test is needed to avoid identifying '{"__proto__":[]}' as an array.
// TODO(sra): Replace this test with cheaper '#.constructor === Array' when
// bug https://code.google.com/p/v8/issues/detail?id=621 is fixed.
if (JS('bool', 'Object.getPrototypeOf(#) !== Array.prototype', object)) {
return new _JsonMap(object);
}
// Update the elements in place since JS arrays are Dart lists.
for (int i = 0; i < JS('int', '#.length', object); i++) {
// Use JS indexing to avoid range checks. We know this is the only
// reference to the list, but the compiler will likely never be able to
// tell that this instance of the list cannot have its length changed by
// the reviver even though it later will be passed to the reviver at the
// outer level.
var item = JS('', '#[#]', object, i);
JS('', '#[#]=#', object, i, _convertJsonToDartLazy(item));
}
return object;
}
class _JsonMap extends MapBase<String, dynamic> {
// The original JavaScript object remains unchanged until
// the map is eventually upgraded, in which case we null it
// out to reclaim the memory used by it.
var _original;
// We keep track of the map entries that we have already
// processed by adding them to a separate JavaScript object.
var _processed = _newJavaScriptObject();
// If the data slot isn't null, it represents either the list
// of keys (for non-upgraded JSON maps) or the upgraded map.
var _data = null;
_JsonMap(this._original);
operator [](key) {
if (_isUpgraded) {
return _upgradedMap[key];
} else if (key is! String) {
return null;
} else {
var result = _getProperty(_processed, key);
if (_isUnprocessed(result)) result = _process(key);
return result;
}
}
int get length => _isUpgraded ? _upgradedMap.length : _computeKeys().length;
bool get isEmpty => length == 0;
bool get isNotEmpty => length > 0;
Iterable<String> get keys {
if (_isUpgraded) return _upgradedMap.keys;
return new _JsonMapKeyIterable(this);
}
Iterable get values {
if (_isUpgraded) return _upgradedMap.values;
return new MappedIterable(_computeKeys(), (each) => this[each]);
}
operator []=(key, value) {
if (_isUpgraded) {
_upgradedMap[key] = value;
} else if (containsKey(key)) {
var processed = _processed;
_setProperty(processed, key, value);
var original = _original;
if (!identical(original, processed)) {
_setProperty(original, key, null); // Reclaim memory.
}
} else {
_upgrade()[key] = value;
}
}
void addAll(Map<String, dynamic> other) {
other.forEach((key, value) {
this[key] = value;
});
}
bool containsValue(value) {
if (_isUpgraded) return _upgradedMap.containsValue(value);
List<String> keys = _computeKeys();
for (int i = 0; i < keys.length; i++) {
String key = keys[i];
if (this[key] == value) return true;
}
return false;
}
bool containsKey(key) {
if (_isUpgraded) return _upgradedMap.containsKey(key);
if (key is! String) return false;
return _hasProperty(_original, key);
}
putIfAbsent(key, ifAbsent()) {
if (containsKey(key)) return this[key];
var value = ifAbsent();
this[key] = value;
return value;
}
remove(Object key) {
if (!_isUpgraded && !containsKey(key)) return null;
return _upgrade().remove(key);
}
void clear() {
if (_isUpgraded) {
_upgradedMap.clear();
} else {
if (_data != null) {
// Clear the list of keys to make sure we force
// a concurrent modification error if anyone is
// currently iterating over it.
_data.clear();
}
_original = _processed = null;
_data = {};
}
}
void forEach(void f(String key, value)) {
if (_isUpgraded) return _upgradedMap.forEach(f);
List<String> keys = _computeKeys();
for (int i = 0; i < keys.length; i++) {
String key = keys[i];
// Compute the value under the assumption that the property
// is present but potentially not processed.
var value = _getProperty(_processed, key);
if (_isUnprocessed(value)) {
value = _convertJsonToDartLazy(_getProperty(_original, key));
_setProperty(_processed, key, value);
}
// Do the callback.
f(key, value);
// Check if invoking the callback function changed
// the key set. If so, throw an exception.
if (!identical(keys, _data)) {
throw new ConcurrentModificationError(this);
}
}
}
// ------------------------------------------
// Private helper methods.
// ------------------------------------------
bool get _isUpgraded => _processed == null;
Map<String, dynamic> get _upgradedMap {
assert(_isUpgraded);
// 'cast' the union type to LinkedHashMap. It would be even better if we
// could 'cast' to the implementation type, since LinkedHashMap includes
// _JsonMap.
return JS('LinkedHashMap', '#', _data);
}
List<String> _computeKeys() {
assert(!_isUpgraded);
List keys = _data;
if (keys == null) {
keys = _data = new JSArray<String>.typed(_getPropertyNames(_original));
}
return JS('JSExtendableArray', '#', keys);
}
Map<String, dynamic> _upgrade() {
if (_isUpgraded) return _upgradedMap;
// Copy all the (key, value) pairs to a freshly allocated
// linked hash map thus preserving the ordering.
var result = <String, dynamic>{};
List<String> keys = _computeKeys();
for (int i = 0; i < keys.length; i++) {
String key = keys[i];
result[key] = this[key];
}
// We only upgrade when we need to extend the map, so we can
// safely force a concurrent modification error in case
// someone is iterating over the map here.
if (keys.isEmpty) {
keys.add(null);
} else {
keys.clear();
}
// Clear out the associated JavaScript objects and mark the
// map as having been upgraded.
_original = _processed = null;
_data = result;
assert(_isUpgraded);
return result;
}
_process(String key) {
if (!_hasProperty(_original, key)) return null;
var result = _convertJsonToDartLazy(_getProperty(_original, key));
return _setProperty(_processed, key, result);
}
// ------------------------------------------
// Private JavaScript helper methods.
// ------------------------------------------
static bool _hasProperty(object, String key) =>
JS('bool', 'Object.prototype.hasOwnProperty.call(#,#)', object, key);
static _getProperty(object, String key) => JS('', '#[#]', object, key);
static _setProperty(object, String key, value) =>
JS('', '#[#]=#', object, key, value);
static List _getPropertyNames(object) =>
JS('JSExtendableArray', 'Object.keys(#)', object);
static bool _isUnprocessed(object) =>
JS('bool', 'typeof(#)=="undefined"', object);
static _newJavaScriptObject() => JS('=Object', 'Object.create(null)');
}
class _JsonMapKeyIterable extends ListIterable<String> {
final _JsonMap _parent;
_JsonMapKeyIterable(this._parent);
int get length => _parent.length;
String elementAt(int index) {
return _parent._isUpgraded
? _parent.keys.elementAt(index)
: _parent._computeKeys()[index];
}
/// Although [ListIterable] defines its own iterator, we return the iterator
/// of the underlying list [_keys] in order to propagate
/// [ConcurrentModificationError]s.
Iterator<String> get iterator {
return _parent._isUpgraded
? _parent.keys.iterator
: _parent._computeKeys().iterator;
}
/// Delegate to [parent.containsKey] to ensure the performance expected
/// from [Map.keys.containsKey].
bool contains(Object key) => _parent.containsKey(key);
}
@patch
class JsonDecoder {
@patch
StringConversionSink startChunkedConversion(Sink<Object> sink) {
return new _JsonDecoderSink(_reviver, sink);
}
}
/// Implements the chunked conversion from a JSON string to its corresponding
/// object.
///
/// The sink only creates one object, but its input can be chunked.
// TODO(floitsch): don't accumulate everything before starting to decode.
class _JsonDecoderSink extends _StringSinkConversionSink {
final Function(Object key, Object value) _reviver;
final Sink<Object> _sink;
_JsonDecoderSink(this._reviver, this._sink) : super(new StringBuffer(''));
void close() {
super.close();
StringBuffer buffer = _stringSink;
String accumulated = buffer.toString();
buffer.clear();
Object decoded = _parseJson(accumulated, _reviver);
_sink.add(decoded);
_sink.close();
}
}
@patch
class Utf8Decoder {
@patch
Converter<List<int>, T> fuse<T>(Converter<String, T> next) {
return super.fuse(next);
}
@patch
static String _convertIntercepted(
bool allowMalformed, List<int> codeUnits, int start, int end) {
// Test `codeUnits is NativeUint8List`. Dart's NativeUint8List is
// implemented by JavaScript's Uint8Array.
if (JS('bool', '# instanceof Uint8Array', codeUnits)) {
// JS 'cast' to avoid a downcast equivalent to the is-check we hand-coded.
NativeUint8List casted = JS('NativeUint8List', '#', codeUnits);
return _convertInterceptedUint8List(allowMalformed, casted, start, end);
}
return null; // This call was not intercepted.
}
static String _convertInterceptedUint8List(
bool allowMalformed, NativeUint8List codeUnits, int start, int end) {
if (allowMalformed) {
// TextDecoder with option {fatal: false} does not produce the same result
// as [Utf8Decoder]. It disagrees on the number of `U+FFFD` (REPLACEMENT
// CHARACTER) generated for some malformed sequences. We could use
// TextDecoder with option {fatal: true}, catch the error, and re-try
// without acceleration. That turns out to be extremely slow (the Error
// captures a stack trace).
// TODO(31370): Bring Utf8Decoder into alignment with TextDecoder.
// TODO(sra): If we can't do that, can we detect valid input fast enough
// to use a check like the [_unsafe] check below?
return null;
}
var decoder = _decoder;
if (decoder == null) return null;
if (0 == start && end == null) {
return _useTextDecoderChecked(decoder, codeUnits);
}
int length = codeUnits.length;
end = RangeError.checkValidRange(start, end, length);
if (0 == start && end == codeUnits.length) {
return _useTextDecoderChecked(decoder, codeUnits);
}
return _useTextDecoderChecked(decoder,
JS('NativeUint8List', '#.subarray(#, #)', codeUnits, start, end));
}
static String _useTextDecoderChecked(decoder, NativeUint8List codeUnits) {
if (_unsafe(codeUnits)) return null;
return _useTextDecoderUnchecked(decoder, codeUnits);
}
static String _useTextDecoderUnchecked(decoder, NativeUint8List codeUnits) {
// If the input is malformed, catch the exception and return `null` to fall
// back on unintercepted decoder. The fallback will either succeed in
// decoding, or report the problem better than TextDecoder.
try {
return JS('String', '#.decode(#)', decoder, codeUnits);
} catch (e) {}
return null;
}
/// Returns `true` if [codeUnits] contains problematic encodings.
///
/// TextDecoder behaves differently to [Utf8Encoder] when the input encodes a
/// surrogate (U+D800 through U+DFFF). TextDecoder considers the surrogate to
/// be an encoding error and, depending on the `fatal` option, either throws
/// and Error or encodes the surrogate as U+FFFD. [Utf8Decoder] does not
/// consider the surrogate to be an error and returns the code unit encoded by
/// the surrogate.
///
/// Throwing an `Error` captures the stack, whoch makes it so expensive that
/// it is worth checking the input for surrogates and avoiding TextDecoder in
/// this case.
static bool _unsafe(NativeUint8List codeUnits) {
// Surrogates encode as (hex) ED Ax xx or ED Bx xx.
int limit = codeUnits.length - 2;
for (int i = 0; i < limit; i++) {
int unit1 = codeUnits[i];
if (unit1 == 0xED) {
int unit2 = codeUnits[i + 1];
if ((unit2 & 0xE0) == 0xA0) return true;
}
}
return false;
}
// TextDecoder is not defined on some browsers and on the stand-alone d8 and
// jsshell engines. Use a lazy initializer to do feature detection once.
static final _decoder = _makeDecoder();
static _makeDecoder() {
try {
// Use `{fatal: true}`. 'fatal' does not correspond exactly to
// `!allowMalformed`: TextDecoder rejects unpaired surrogates which
// [Utf8Decoder] accepts. In non-fatal mode, TextDecoder translates
// unpaired surrogates to REPLACEMENT CHARACTER (U+FFFD) whereas
// [Utf8Decoder] leaves the surrogate intact.
return JS('', 'new TextDecoder("utf-8", {fatal: true})');
} catch (e) {}
return null;
}
}
@patch
int _scanOneByteCharacters(List<int> units, int from, int endIndex) {
final to = endIndex;
for (var i = from; i < to; i++) {
final unit = units[i];
if ((unit & _ONE_BYTE_LIMIT) != unit) return i - from;
}
return to - from;
}

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more