Initial checkin.

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@15 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
dgrove@google.com 2011-10-05 05:20:07 +00:00
parent 6e10bccb64
commit 4c0f559d23
394 changed files with 97455 additions and 0 deletions

46
runtime/PRESUBMIT.py Normal file
View file

@ -0,0 +1,46 @@
# Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
import cpplint
import os
def RunLint(input_api, output_api):
result = []
cpplint._cpplint_state.ResetErrorCounts()
# Find all .cc and .h files in the change list.
for svn_file in input_api.AffectedTextFiles():
filename = svn_file.AbsoluteLocalPath()
if filename.endswith('.cc') or filename.endswith('.h'):
hacked_parent_svn = 0
if filename.endswith('.h'):
parent_path = os.path.dirname(input_api.PresubmitLocalPath())
orig_path = os.path.join(parent_path, '.svn')
renamed_path = os.path.join(parent_path, '.svn_orig')
if (os.path.exists(renamed_path)):
error_msg = '".svn_orig" exists in presubmit parent directory('
error_msg += parent_path
error_msg += '). Consider renaming it manually to ".svn".'
result = [output_api.PresubmitError(error_msg)]
return result
if (os.path.exists(orig_path)):
# Make the parent SVN directory non-discoverable by cpplint to get
# the correct header guard checks. This is needed if using all Dart
# checkout.
os.rename(orig_path, renamed_path)
hacked_parent_svn = 1
# Run cpplint on the file.
cpplint.ProcessFile(filename, 1)
if hacked_parent_svn != 0:
# Undo hacks from above: Restore the original name.
os.rename(renamed_path, orig_path)
# Report a presubmit error if any of the files had an error.
if cpplint._cpplint_state.error_count > 0:
result = [output_api.PresubmitError('Failed cpplint check.')]
return result
def CheckChangeOnUpload(input_api, output_api):
return RunLint(input_api, output_api)
def CheckChangeOnCommit(input_api, output_api):
return RunLint(input_api, output_api)

411
runtime/bin/bin.gypi Normal file
View file

@ -0,0 +1,411 @@
# Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
{
'variables': {
'builtin_in_cc_file': 'builtin_in.cc',
'builtin_cc_file': '<(SHARED_INTERMEDIATE_DIR)/builtin_gen.cc',
'snapshot_in_cc_file': 'snapshot_in.cc',
'snapshot_bin_file': '<(SHARED_INTERMEDIATE_DIR)/snapshot_gen.bin',
'snapshot_cc_file': '<(SHARED_INTERMEDIATE_DIR)/snapshot_gen.cc',
},
'targets': [
{
'target_name': 'generate_builtin_cc_file',
'type': 'none',
'conditions': [
['OS=="win"', {
'msvs_cygwin_dirs': ['<(DEPTH)/../third_party/cygwin'],
}],
],
'sources': [
'builtin.dart',
'directory.dart',
'directory_impl.dart',
'eventhandler.dart',
'file.dart',
'file_impl.dart',
'input_stream.dart',
'output_stream.dart',
'process.dart',
'process_impl.dart',
'socket.dart',
'socket_impl.dart',
'socket_stream.dart',
'timer.dart',
'timer_impl.dart',
],
'actions': [
{
'action_name': 'generate_builtin_cc',
'inputs': [
'../tools/create_string_literal.py',
'<(builtin_in_cc_file)',
'<@(_sources)',
],
'outputs': [
'<(builtin_cc_file)',
],
'action': [
'python',
'tools/create_string_literal.py',
'--output', '<(builtin_cc_file)',
'--input_cc', '<(builtin_in_cc_file)',
'<@(_sources)',
],
'message': 'Generating ''<(builtin_cc_file)'' file.'
},
]
},
{
'target_name': 'libdart_builtin',
'type': 'static_library',
'dependencies': [
'generate_builtin_cc_file',
],
'include_dirs': [
'..',
],
'sources': [
'builtin.cc',
'builtin.h',
'dartutils.h',
'dartutils.cc',
'directory.h',
'directory.cc',
'directory_linux.cc',
'directory_macos.cc',
'directory_win.cc',
'eventhandler.cc',
'eventhandler.h',
'eventhandler_linux.cc',
'eventhandler_linux.h',
'eventhandler_macos.cc',
'eventhandler_macos.h',
'eventhandler_win.cc',
'eventhandler_win.h',
'file.cc',
'file.h',
'file_linux.cc',
'file_macos.cc',
'file_win.cc',
'fdutils.h',
'fdutils_linux.cc',
'fdutils_macos.cc',
'globals.h',
'process.cc',
'process.h',
'process_linux.cc',
'process_macos.cc',
'process_win.cc',
'socket.cc',
'socket.h',
'socket_linux.cc',
'socket_macos.cc',
'socket_win.cc',
'set.h',
# Include generated source files.
'<(builtin_cc_file)',
],
'conditions': [
['OS=="win"', {'sources/' : [
['exclude', 'fdutils.h'],
]}],
],
},
{
# Standalone executable using the shared libdart library.
'target_name': 'dart_no_snapshot',
'type': 'executable',
'dependencies': [
'libdart',
'libdart_builtin',
],
'include_dirs': [
'..',
],
'sources': [
'main.cc',
'process_script.cc',
'process_script.h',
'snapshot_empty.cc',
],
'conditions': [
['OS=="win"', {
'link_settings': {
'libraries': [ '-lws2_32.lib' ],
},
}]],
},
{
# Completely statically linked dart binary.
'target_name': 'dart_no_snapshot_bin',
'type': 'executable',
'dependencies': [
'libdart_lib',
'libdart_vm',
'libjscre',
'libdart_api',
'libdart_builtin',
],
'include_dirs': [
'..',
],
'sources': [
'main.cc',
'process_script.cc',
'process_script.h',
'snapshot_empty.cc',
],
'conditions': [
['OS=="win"', {
'link_settings': {
'libraries': [ '-lws2_32.lib' ],
},
}]],
},
{
# Completely statically linked binary for generating snapshots.
'target_name': 'gen_snapshot_bin',
'type': 'executable',
'dependencies': [
'libdart_lib',
'libdart_vm',
'libjscre',
'libdart_api',
'libdart_builtin',
],
'include_dirs': [
'..',
],
'sources': [
'gen_snapshot.cc',
'process_script.cc',
'process_script.h',
],
'conditions': [
['OS=="win"', {
'link_settings': {
'libraries': [ '-lws2_32.lib' ],
},
}]],
},
{
# Generate snapshot file.
'target_name': 'generate_snapshot_file',
'type': 'none',
'conditions': [
['OS=="win"', {
'msvs_cygwin_dirs': ['<(DEPTH)/../third_party/cygwin'],
}],
],
'dependencies': [
'gen_snapshot_bin',
],
'actions': [
{
'action_name': 'generate_snapshot_file',
'inputs': [
'../tools/create_snapshot_file.py',
'<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)gen_snapshot_bin<(EXECUTABLE_SUFFIX)',
'<(snapshot_in_cc_file)',
],
'outputs': [
'<(snapshot_cc_file)',
],
'action': [
'python',
'tools/create_snapshot_file.py',
'--executable', '<(PRODUCT_DIR)/gen_snapshot_bin',
'--output_bin', '<(snapshot_bin_file)',
'--input_cc', '<(snapshot_in_cc_file)',
'--output', '<(snapshot_cc_file)',
],
'message': 'Generating ''<(snapshot_cc_file)'' file.'
},
]
},
{
# Standalone executable using the shared libdart library with a snapshot
# of the core and builtin libraries linked in.
'target_name': 'dart',
'type': 'executable',
'dependencies': [
'libdart',
'libdart_builtin',
'generate_snapshot_file',
],
'include_dirs': [
'..',
],
'sources': [
'main.cc',
'process_script.cc',
'process_script.h',
'<(snapshot_cc_file)',
],
'conditions': [
['OS=="win"', {
'link_settings': {
'libraries': [ '-lws2_32.lib' ],
},
}]],
},
{
# Completely statically linked dart binary with a snapshot of the core
# and builtin libraries linked in.
'target_name': 'dart_bin',
'type': 'executable',
'dependencies': [
'libdart_lib',
'libdart_vm',
'libjscre',
'libdart_api',
'libdart_builtin',
'generate_snapshot_file',
],
'include_dirs': [
'..',
],
'sources': [
'main.cc',
'process_script.cc',
'process_script.h',
'<(snapshot_cc_file)',
],
'conditions': [
['OS=="win"', {
'link_settings': {
'libraries': [ '-lws2_32.lib' ],
},
}]],
},
{
'target_name': 'process_test',
'type': 'executable',
'sources': [
'process_test.cc',
]
},
{
'target_name': 'run_vm_tests',
'type': 'executable',
# The unittest framework needs to be able to call the unexported symbols,
# which is why it links against the static libraries. In general binaries
# should depend on the shared library.
'dependencies': [
'libdart_lib',
'libdart_vm',
'libjscre',
'libdart_api',
'generate_snapshot_test_dat_file',
],
'include_dirs': [
'..',
'<(SHARED_INTERMEDIATE_DIR)',
],
'sources': [
'run_vm_tests.cc',
'dartutils.h',
'dartutils.cc',
'directory.h',
'directory.cc',
'directory_linux.cc',
'directory_macos.cc',
'directory_win.cc',
'eventhandler.cc',
'eventhandler.h',
'eventhandler_linux.cc',
'eventhandler_linux.h',
'eventhandler_macos.cc',
'eventhandler_macos.h',
'eventhandler_win.cc',
'eventhandler_win.h',
'file.cc',
'file.h',
'file_test.cc',
'file_linux.cc',
'file_macos.cc',
'file_win.cc',
'fdutils.h',
'fdutils_linux.cc',
'fdutils_macos.cc',
'process.cc',
'process.h',
'process_linux.cc',
'process_macos.cc',
'process_win.cc',
'socket.cc',
'socket.h',
'socket_linux.cc',
'socket_macos.cc',
'socket_win.cc',
'set.h',
'set_test.cc',
],
'includes': [
'../vm/vm_sources.gypi',
],
'defines': [
'TESTING',
],
# Only include _test.[cc|h] files.
'sources/': [
['exclude', '\\.(cc|h)$'],
['include', '_test\\.(cc|h)$'],
['include', 'run_vm_tests.cc'],
['include', 'dart_api_impl.cc'],
['include', 'dartutils.h'],
['include', 'dartutils.cc'],
['include', 'directory.h'],
['include', 'directory.cc'],
['include', 'eventhandler.cc'],
['include', 'eventhandler.h'],
['include', 'file.cc'],
['include', 'file.h'],
['include', 'file_test.cc'],
['include', 'process.cc'],
['include', 'process.h'],
['include', 'socket.cc'],
['include', 'socket.h'],
['include', 'set_test.cc'],
],
'conditions': [
['OS=="linux"', {'sources/' : [
['include', 'directory_linux.cc'],
['include', 'eventhandler_linux.cc'],
['include', 'eventhandler_linux.h'],
['include', 'fdutils.h'],
['include', 'fdutils_linux.cc'],
['include', 'file_linux.cc'],
['include', 'process_linux.cc'],
['include', 'socket_linux.cc'],
]}],
['OS=="mac"', {'sources/' : [
['include', 'directory_macos.cc'],
['include', 'eventhandler_macos.cc'],
['include', 'eventhandler_macos.h'],
['include', 'fdutils.h'],
['include', 'fdutils_macos.cc'],
['include', 'file_macos.cc'],
['include', 'process_macos.cc'],
['include', 'socket_macos.cc'],
]}],
['OS=="win"', {'sources/' : [
['include', 'directory_win.cc'],
['include', 'eventhandler_win.cc'],
['include', 'eventhandler_win.h'],
['include', 'file_win.cc'],
['include', 'process_win.cc'],
['include', 'socket_win.cc'],
]}],
['OS=="win"', {
'link_settings': {
'libraries': [ '-lws2_32.lib' ],
},
}],
],
},
],
}

29
runtime/bin/builtin.cc Normal file
View file

@ -0,0 +1,29 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "include/dart_api.h"
#include "bin/builtin.h"
// Implementation of native functions which are used for some
// test/debug functionality in standalone dart mode.
void PrintString(FILE* out, Dart_Handle string) {
Dart_Result result = Dart_StringToCString(string);
const char* cstring = Dart_IsValidResult(result) ?
Dart_GetResultAsCString(result) : Dart_GetErrorCString(result);
fprintf(out, "%s\n", cstring);
}
void FUNCTION_NAME(Logger_PrintString)(Dart_NativeArguments args) {
Dart_EnterScope();
PrintString(stdout, Dart_GetNativeArgument(args, 0));
Dart_ExitScope();
}

13
runtime/bin/builtin.dart Normal file
View file

@ -0,0 +1,13 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#library("builtin");
void print(arg) {
_Logger._printString(arg.toString());
}
class _Logger {
static void _printString(String s) native "Logger_PrintString";
}

42
runtime/bin/builtin.h Normal file
View file

@ -0,0 +1,42 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef BIN_BUILTIN_H_
#define BIN_BUILTIN_H_
#include <stdio.h>
#include <stdlib.h>
#include "bin/globals.h"
#include "include/dart_api.h"
#ifdef DEBUG
#define ASSERT(expr) assert(expr)
#else
#define ASSERT(expr) USE(expr)
#endif
#define FATAL(error) \
fprintf(stderr, "%s\n", error); \
fflush(stderr); \
abort();
#define UNREACHABLE() \
FATAL("unreachable code")
#define UNIMPLEMENTED() \
FATAL("unimplemented code")
#define FUNCTION_NAME(name) Builtin_##name
#define REGISTER_FUNCTION(name, count) \
{ ""#name, FUNCTION_NAME(name), count },
#define DECLARE_FUNCTION(name, count) \
extern void FUNCTION_NAME(name)(Dart_NativeArguments args);
extern void Builtin_LoadLibrary();
extern void Builtin_ImportLibrary(Dart_Handle library);
extern void Builtin_SetNativeResolver();
extern void PrintString(FILE* out, Dart_Handle object);
#endif // BIN_BUILTIN_H_

156
runtime/bin/builtin_in.cc Normal file
View file

@ -0,0 +1,156 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "include/dart_api.h"
#include "bin/builtin.h"
#include "bin/dartutils.h"
// The string on the next line will be filled in with the contents of the
// builtin.dart file.
// This string forms the content of builtin functionality which is injected
// into standalone dart to provide some test/debug functionality.
static const char Builtin_source_[] = {
%s
};
// List all native functions implemented in standalone dart that is used
// to inject additional functionality e.g: Logger, file I/O, socket I/O etc.
#define BUILTIN_NATIVE_LIST(V) \
V(Logger_PrintString, 1) \
V(Directory_Close, 2) \
V(Directory_List, 7) \
V(Directory_Open, 2) \
V(File_OpenFile, 3) \
V(File_Exists, 1) \
V(File_Close, 1) \
V(File_ReadByte, 1) \
V(File_WriteByte, 2) \
V(File_WriteString, 2) \
V(File_ReadList, 4) \
V(File_WriteList , 4) \
V(File_Position, 1) \
V(File_Length, 1) \
V(File_Flush, 1) \
V(EventHandler_Start, 1) \
V(EventHandler_SendData, 4) \
V(Process_Kill, 2) \
V(Process_Start, 8) \
V(Socket_CreateConnect, 3) \
V(Socket_Available, 1) \
V(Socket_ReadList, 4) \
V(Socket_WriteList, 4) \
V(Socket_GetPort, 1) \
V(ServerSocket_CreateBindListen, 4) \
V(ServerSocket_Accept, 2) \
BUILTIN_NATIVE_LIST(DECLARE_FUNCTION);
static struct NativeEntries {
const char* name_;
Dart_NativeFunction function_;
int argument_count_;
} BuiltinEntries[] = {
BUILTIN_NATIVE_LIST(REGISTER_FUNCTION)
};
static Dart_NativeFunction native_lookup(Dart_Handle name,
int argument_count) {
Dart_Result result = Dart_StringToCString(name);
assert(Dart_IsValidResult(result));
const char* function_name = Dart_GetResultAsCString(result);
assert(function_name != NULL);
int num_entries = sizeof(BuiltinEntries) / sizeof(struct NativeEntries);
for (int i = 0; i < num_entries; i++) {
struct NativeEntries* entry = &(BuiltinEntries[i]);
if (!strcmp(function_name, entry->name_)) {
if (entry->argument_count_ == argument_count) {
return reinterpret_cast<Dart_NativeFunction>(entry->function_);
} else {
// Wrong number of arguments.
// TODO(regis): Should we pass a buffer for error reporting?
return NULL;
}
}
}
return NULL;
}
void Builtin_LoadLibrary() {
Dart_Handle url = Dart_NewString(DartUtils::kBuiltinLibURL);
Dart_Result result = Dart_LookupLibrary(url);
if (Dart_IsValidResult(result)) {
// Builtin library already loaded.
return;
}
// Load the library.
Dart_Handle source = Dart_NewString(Builtin_source_);
result = Dart_LoadLibrary(url, source);
assert(Dart_IsValidResult(result));
Dart_Handle builtin_lib = Dart_GetResult(result);
// Lookup the core libraries and inject the builtin library into them.
result = Dart_LookupLibrary(Dart_NewString("dart:core"));
assert(Dart_IsValidResult(result));
Dart_Handle core_lib = Dart_GetResult(result);
result = Dart_LibraryImportLibrary(core_lib, builtin_lib);
assert(Dart_IsValidResult(result));
result = Dart_LookupLibrary(Dart_NewString("dart:coreimpl"));
assert(Dart_IsValidResult(result));
Dart_Handle coreimpl_lib = Dart_GetResult(result);
result = Dart_LibraryImportLibrary(coreimpl_lib, builtin_lib);
assert(Dart_IsValidResult(result));
result = Dart_LibraryImportLibrary(builtin_lib, coreimpl_lib);
assert(Dart_IsValidResult(result));
// Create a native wrapper "FileNativeWrapper" so that we can add a
// native field to store the OS file handle for implementing all the
// file operations. The class "File" extends "FileNativeWrapper".
Dart_Handle name = Dart_NewString("FileNativeWrapper");
const int kNumFileFields = 1;
result = Dart_CreateNativeWrapperClass(builtin_lib, name, kNumFileFields);
assert(Dart_IsValidResult(result));
// Create a native wrapper "EventHandlerNativeWrapper" so that we can add a
// native field to store the event handle for implementing all
// event operations.
name = Dart_NewString("EventHandlerNativeWrapper");
const int kNumEventHandlerFields = 1;
result = Dart_CreateNativeWrapperClass(builtin_lib,
name,
kNumEventHandlerFields);
assert(Dart_IsValidResult(result));
}
void Builtin_ImportLibrary(Dart_Handle library) {
Builtin_LoadLibrary();
Dart_Handle url = Dart_NewString(DartUtils::kBuiltinLibURL);
Dart_Result result = Dart_LookupLibrary(url);
assert(Dart_IsValidResult(result));
Dart_Handle builtin_lib = Dart_GetResult(result);
result = Dart_LibraryImportLibrary(library, builtin_lib);
assert(Dart_IsValidResult(result));
}
void Builtin_SetNativeResolver() {
Dart_Handle url = Dart_NewString(DartUtils::kBuiltinLibURL);
Dart_Result result = Dart_LookupLibrary(url);
assert(Dart_IsValidResult(result));
Dart_Handle builtin_lib = Dart_GetResult(result);
result = Dart_SetNativeResolver(builtin_lib, native_lookup);
assert(Dart_IsValidResult(result));
}

57
runtime/bin/dartutils.cc Normal file
View file

@ -0,0 +1,57 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "bin/dartutils.h"
const char* DartUtils::kBuiltinLibURL = "./dart:builtin-lib";
const char* DartUtils::kBuiltinLibSpec = "library { }";
const char* DartUtils::kIdFieldName = "_id";
int64_t DartUtils::GetIntegerValue(Dart_Handle value_obj) {
assert(Dart_IsInteger(value_obj));
Dart_Result result = Dart_IntegerValue(value_obj);
ASSERT(Dart_IsValidResult(result));
return Dart_GetResultAsCInt64(result);
}
const char* DartUtils::GetStringValue(Dart_Handle str_obj) {
Dart_Result result = Dart_StringToCString(str_obj);
ASSERT(Dart_IsValidResult(result));
return Dart_GetResultAsCString(result);
}
bool DartUtils::GetBooleanValue(Dart_Handle bool_obj) {
Dart_Result result = Dart_BooleanValue(bool_obj);
ASSERT(Dart_IsValidResult(result));
return Dart_GetResultAsCBoolean(result);
}
void DartUtils::SetIntegerInstanceField(Dart_Handle handle,
const char* name,
intptr_t val) {
Dart_Result result = Dart_SetInstanceField(handle,
Dart_NewString(name),
Dart_NewInteger(val));
ASSERT(Dart_IsValidResult(result));
}
intptr_t DartUtils::GetIntegerInstanceField(Dart_Handle handle,
const char* name) {
Dart_Result result =
Dart_GetInstanceField(handle, Dart_NewString(name));
assert(Dart_IsValidResult(result));
intptr_t value = DartUtils::GetIntegerValue(Dart_GetResult(result));
return value;
}
void DartUtils::SetStringInstanceField(Dart_Handle handle,
const char* name,
const char* val) {
Dart_Result result = Dart_SetInstanceField(handle,
Dart_NewString(name),
Dart_NewString(val));
ASSERT(Dart_IsValidResult(result));
}

36
runtime/bin/dartutils.h Normal file
View file

@ -0,0 +1,36 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef BIN_DARTUTILS_H_
#define BIN_DARTUTILS_H_
#include "bin/builtin.h"
#include "bin/globals.h"
#include "include/dart_api.h"
class DartUtils {
public:
static int64_t GetIntegerValue(Dart_Handle value_obj);
static const char* GetStringValue(Dart_Handle str_obj);
static bool GetBooleanValue(Dart_Handle bool_obj);
static void SetIntegerInstanceField(Dart_Handle handle,
const char* name,
intptr_t val);
static intptr_t GetIntegerInstanceField(Dart_Handle handle,
const char* name);
static void SetStringInstanceField(Dart_Handle handle,
const char* name,
const char* val);
static const char* kBuiltinLibURL;
static const char* kBuiltinLibSpec;
static const char* kIdFieldName;
private:
DISALLOW_ALLOCATION();
DISALLOW_IMPLICIT_CONSTRUCTORS(DartUtils);
};
#endif // BIN_DARTUTILS_H_

65
runtime/bin/directory.cc Normal file
View file

@ -0,0 +1,65 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "bin/dartutils.h"
#include "bin/directory.h"
#include "include/dart_api.h"
void FUNCTION_NAME(Directory_Open)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle directory_handle = Dart_GetNativeArgument(args, 0);
Dart_Handle path_handle = Dart_GetNativeArgument(args, 1);
if (!Dart_IsString(path_handle)) {
Dart_SetReturnValue(args, Dart_NewBoolean(false));
} else {
const char* path =
DartUtils::GetStringValue(path_handle);
intptr_t dir = 0;
bool success = Directory::Open(path, &dir);
if (success) {
DartUtils::SetIntegerInstanceField(directory_handle,
DartUtils::kIdFieldName,
dir);
}
Dart_SetReturnValue(args, Dart_NewBoolean(success));
}
Dart_ExitScope();
}
void FUNCTION_NAME(Directory_Close)(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t dir = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 1));
bool success = Directory::Close(dir);
Dart_SetReturnValue(args, Dart_NewBoolean(success));
Dart_ExitScope();
}
static intptr_t GetHandlerPort(Dart_Handle handle) {
if (Dart_IsNull(handle)) {
// TODO(ager): Generalize this to Directory::kInvalidId.
return 0;
}
return DartUtils::GetIntegerInstanceField(handle, DartUtils::kIdFieldName);
}
void FUNCTION_NAME(Directory_List)(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t dir = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 1));
bool recursive = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 2));
Dart_Port dir_handler_port = GetHandlerPort(Dart_GetNativeArgument(args, 3));
Dart_Port file_handler_port = GetHandlerPort(Dart_GetNativeArgument(args, 4));
Dart_Port done_handler_port = GetHandlerPort(Dart_GetNativeArgument(args, 5));
Dart_Port dir_error_handler_port =
GetHandlerPort(Dart_GetNativeArgument(args, 6));
Directory::List(dir,
recursive,
dir_handler_port,
file_handler_port,
done_handler_port,
dir_error_handler_port);
Dart_ExitScope();
}

View file

@ -0,0 +1,57 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
interface Directory factory DirectoryImpl {
/**
* Creates a directory object. The path is either a full path or
* relative to the directory in which the Dart VM was
* started. Throws an exception if the path does not specify a
* directory.
*/
Directory.open(String dir);
/**
* Close this [Directory]. Terminates listing operation if one is in
* progress. Returns a boolean indicating whether the close operation
* succeeded.
*/
bool close();
/**
* List the sub-directories and files of this
* [Directory]. Optionally recurse into sub-directories. For each
* file and directory, the file or directory handler is called. When
* all directories have been listed the done handler is called. If
* the listing operation is recursive, the directory error handler
* is called if a subdirectory cannot be opened for listing.
*/
void list([bool recursive]);
/**
* Sets the directory handler that is called for all directories
* during listing operations. The directory handler is called with
* the full path of the directory.
*/
void setDirHandler(void dirHandler(String dir));
/**
* Sets the file handler that is called for all directories during
* listing operations. The directory handler is called with the full
* path of the file.
*/
void setFileHandler(void fileHandler(String file));
/**
* Set the done handler that is called either when a directory
* listing is completed or when the close method is called.
*/
void setDoneHandler(void doneHandler(bool completed));
/**
* Set the directory error handler that is called for all
* directories that cannot be opened for listing during recursive
* listing.
*/
void setDirErrorHandler(void errorHandler(String dir));
}

26
runtime/bin/directory.h Normal file
View file

@ -0,0 +1,26 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef BIN_DIRECTORY_H_
#define BIN_DIRECTORY_H_
#include "bin/builtin.h"
#include "bin/globals.h"
class Directory {
public:
static bool Open(const char* path, intptr_t* dir);
static bool Close(intptr_t dir);
static void List(intptr_t dir,
bool recursive,
Dart_Port dir_handler,
Dart_Port file_handler,
Dart_Port done_handler,
Dart_Port dir_error_handler);
DISALLOW_ALLOCATION();
DISALLOW_IMPLICIT_CONSTRUCTORS(Directory);
};
#endif // BIN_DIRECTORY_H_

View file

@ -0,0 +1,130 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
class DirectoryException {
const DirectoryException(String this.message);
final String message;
}
class DirectoryImpl implements Directory {
DirectoryImpl.open(String dir) {
_id = 0;
_closed = false;
_listing = false;
if (!_open(dir)) {
_closed = true;
throw new DirectoryException("Error: could not open directory");
}
}
bool close() {
if (_closed) {
throw new DirectoryException("Error: directory closed");
}
if (_close(_id)) {
_closePort(_dirHandler);
_closePort(_fileHandler);
_closePort(_doneHandler);
_closePort(_dirErrorHandler);
_closed = true;
bool was_listing = _listing;
_listing = false;
if (was_listing && _doneHandler !== null) {
_doneHandler(false);
}
return true;
}
return false;
}
void list([bool recursive = false]) {
if (_closed) {
throw new DirectoryException("Error: directory closed");
}
if (_listing) {
throw new DirectoryException("Error: listing already in progress");
}
_listing = true;
_list(_id,
recursive,
_dirHandler,
_fileHandler,
_doneHandler,
_dirErrorHandler);
}
// TODO(ager): Implement setting of the handlers as in the process library.
void setDirHandler(void dirHandler(String dir)) {
if (_closed) {
throw new DirectoryException("Error: directory closed");
}
if (_dirHandler === null) {
_dirHandler = new ReceivePort();
}
_dirHandler.receive((String dir, ignored) => dirHandler(dir));
}
void setFileHandler(void fileHandler(String file)) {
if (_closed) {
throw new DirectoryException("Error: directory closed");
}
if (_fileHandler === null) {
_fileHandler = new ReceivePort();
}
_fileHandler.receive((String file, ignored) => fileHandler(file));
}
void setDoneHandler(void doneHandler(bool completed)) {
if (_closed) {
throw new DirectoryException("Error: directory closed");
}
if (_doneHandler === null) {
_doneHandler = new ReceivePort();
}
_doneHandler.receive((bool completed, ignored) {
_listing = false;
doneHandler(completed);
});
}
void setDirErrorHandler(void errorHandler(String dir)) {
if (_closed) {
throw new DirectoryException("Error: directory closed");
}
if (_dirErrorHandler === null) {
_dirErrorHandler = new ReceivePort();
}
_dirErrorHandler.receive((String dir, ignored) {
errorHandler(dir, completed);
});
}
// Utility methods.
void _closePort(ReceivePort port) {
if (port !== null) {
port.close();
}
}
// Native code binding.
bool _open(String dir) native "Directory_Open";
bool _close(int id) native "Directory_Close";
void _list(int id,
bool recursive,
ReceivePort dirHandler,
ReceivePort fileHandler,
ReceivePort doneHandler,
ReceivePort dirErrorHandler) native "Directory_List";
ReceivePort _dirHandler;
ReceivePort _fileHandler;
ReceivePort _doneHandler;
ReceivePort _dirErrorHandler;
int _id;
bool _closed;
bool _listing;
}

View file

@ -0,0 +1,72 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include "bin/directory.h"
bool Directory::Open(const char* path, intptr_t* dir) {
DIR* dir_pointer = opendir(path);
if (dir_pointer == NULL) {
return false;
}
*dir = reinterpret_cast<intptr_t>(dir_pointer);
return true;
}
bool Directory::Close(intptr_t dir) {
DIR* dir_pointer = reinterpret_cast<DIR*>(dir);
int result = closedir(dir_pointer);
return result == 0;
}
void Directory::List(intptr_t dir,
bool recursive,
Dart_Port dir_handler,
Dart_Port file_handler,
Dart_Port done_handler,
Dart_Port dir_error_handler) {
// TODO(ager): Handle recursion and errors caused by recursion.
// TODO(ager): Make this async by using a thread to do this.
DIR* dir_pointer = reinterpret_cast<DIR*>(dir);
int success = 0;
dirent entry;
dirent* result;
while ((success = readdir_r(dir_pointer, &entry, &result)) == 0 &&
result != NULL) {
switch (entry.d_type) {
case DT_DIR:
if (dir_handler != 0 &&
strcmp(entry.d_name, ".") != 0 &&
strcmp(entry.d_name, "..") != 0) {
Dart_Handle name = Dart_NewString(entry.d_name);
Dart_Post(dir_handler, name);
}
break;
case DT_REG:
if (file_handler != 0) {
Dart_Handle name = Dart_NewString(entry.d_name);
Dart_Post(file_handler, name);
}
break;
case DT_UNKNOWN:
UNIMPLEMENTED();
// TODO(ager): Handle this correctly. Use lstat or something?
break;
default:
// TODO(ager): Handle symbolic links?
break;
}
}
if (success != 0) {
// TODO(ager): Error listing directory. There should probably be
// a general error handler. Maybe collaps the dir_error_handler
// to just be a general error handler.
} else if (done_handler != 0) {
Dart_Handle value = Dart_NewBoolean(true);
Dart_Post(done_handler, value);
}
}

View file

@ -0,0 +1,72 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include "bin/directory.h"
bool Directory::Open(const char* path, intptr_t* dir) {
DIR* dir_pointer = opendir(path);
if (dir_pointer == NULL) {
return false;
}
*dir = reinterpret_cast<intptr_t>(dir_pointer);
return true;
}
bool Directory::Close(intptr_t dir) {
DIR* dir_pointer = reinterpret_cast<DIR*>(dir);
int result = closedir(dir_pointer);
return result == 0;
}
void Directory::List(intptr_t dir,
bool recursive,
Dart_Port dir_handler,
Dart_Port file_handler,
Dart_Port done_handler,
Dart_Port dir_error_handler) {
// TODO(ager): Handle recursion and errors caused by recursion.
// TODO(ager): Make this async by using a thread to do this.
DIR* dir_pointer = reinterpret_cast<DIR*>(dir);
int success = 0;
dirent entry;
dirent* result;
while ((success = readdir_r(dir_pointer, &entry, &result)) == 0 &&
result != NULL) {
switch (entry.d_type) {
case DT_DIR:
if (dir_handler != 0 &&
strcmp(entry.d_name, ".") != 0 &&
strcmp(entry.d_name, "..") != 0) {
Dart_Handle name = Dart_NewString(entry.d_name);
Dart_Post(dir_handler, name);
}
break;
case DT_REG:
if (file_handler != 0) {
Dart_Handle name = Dart_NewString(entry.d_name);
Dart_Post(file_handler, name);
}
break;
case DT_UNKNOWN:
UNIMPLEMENTED();
// TODO(ager): Handle this correctly. Use lstat or something?
break;
default:
// TODO(ager): Handle symbolic links?
break;
}
}
if (success != 0) {
// TODO(ager): Error listing directory. There should probably be
// a general error handler. Maybe collaps the dir_error_handler
// to just be a general error handler.
} else if (done_handler != 0) {
Dart_Handle value = Dart_NewBoolean(true);
Dart_Post(done_handler, value);
}
}

View file

@ -0,0 +1,24 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "bin/directory.h"
bool Directory::Open(const char* path, intptr_t* dir) {
UNIMPLEMENTED();
return false;
}
bool Directory::Close(intptr_t dir) {
UNIMPLEMENTED();
return false;
}
void Directory::List(intptr_t dir,
bool recursive,
Dart_Port dir_handler,
Dart_Port file_handler,
Dart_Port done_handler,
Dart_Port dir_error_handler) {
UNIMPLEMENTED();
}

View file

@ -0,0 +1,68 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "bin/eventhandler.h"
#include "bin/dartutils.h"
#include "include/dart_api.h"
static const intptr_t kNativeEventHandlerFieldIndex = 0;
/*
* Returns the reference of the EventHandler stored in the native field.
*/
static EventHandler* GetEventHandler(Dart_Handle handle) {
Dart_Result result = Dart_GetNativeInstanceField(
handle, kNativeEventHandlerFieldIndex);
assert(Dart_IsValidResult(result));
EventHandler* event_handler =
reinterpret_cast<EventHandler*>(Dart_GetResultAsCIntptr(result));
assert(event_handler != NULL);
return event_handler;
}
/*
* Sets the reference of the EventHandler in the native field.
*/
static void SetEventHandler(Dart_Handle handle, EventHandler* event_handler) {
Dart_SetNativeInstanceField(handle,
kNativeEventHandlerFieldIndex,
reinterpret_cast<intptr_t>(event_handler));
}
/*
* Starts the EventHandler thread and stores its reference in the dart
* EventHandler object. args[0] holds the reference to the dart EventHandler
* object.
*/
void FUNCTION_NAME(EventHandler_Start)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle handle = Dart_GetNativeArgument(args, 0);
EventHandler* event_handler = EventHandler::StartEventHandler();
SetEventHandler(handle, event_handler);
Dart_ExitScope();
}
/*
* Send data to the EventHandler thread to register for a given instance
* args[1] a ReceivePort args[2] with a notification event args[3]. args[0]
* holds the reference to the dart EventHandler object.
*/
void FUNCTION_NAME(EventHandler_SendData)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle handle = Dart_GetNativeArgument(args, 0);
EventHandler* event_handler = GetEventHandler(handle);
intptr_t id = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 1));
handle = Dart_GetNativeArgument(args, 2);
Dart_Port dart_port =
DartUtils::GetIntegerInstanceField(handle, DartUtils::kIdFieldName);
intptr_t data = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 3));
event_handler->SendData(id, dart_port, data);
Dart_ExitScope();
}

View file

@ -0,0 +1,28 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
class EventHandler extends EventHandlerNativeWrapper {
EventHandler() { }
static void _start() {
if (_eventHandler === null) {
_eventHandler = new EventHandler();
_eventHandler._doStart();
}
}
void _doStart() native "EventHandler_Start";
static _sendData(int id, ReceivePort receivePort, int data) {
if (_eventHandler !== null) {
_eventHandler._doSendData(id, receivePort, data);
}
}
void _doSendData(int id, ReceivePort receivePort, int data)
native "EventHandler_SendData";
static EventHandler _eventHandler;
}

View file

@ -0,0 +1,50 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef BIN_EVENTHANDLER_H_
#define BIN_EVENTHANDLER_H_
#include "bin/builtin.h"
// The event handler delegation class is OS specific.
#if defined(TARGET_OS_LINUX)
#include "bin/eventhandler_linux.h"
#elif defined(TARGET_OS_MACOS)
#include "bin/eventhandler_macos.h"
#elif defined(TARGET_OS_WINDOWS)
#include "bin/eventhandler_win.h"
#else
#error Unknown target os.
#endif
/*
* Keep these constant in sync with the dart poll event identifiers.
*/
enum Message {
kInEvent = 0,
kOutEvent,
kErrorEvent,
kCloseEvent,
kCloseCommand,
};
class EventHandler {
public:
void SendData(intptr_t id, Dart_Port dart_port, intptr_t data) {
delegate_.SendData(id, dart_port, data);
}
static EventHandler* StartEventHandler() {
EventHandler* handler = new EventHandler();
handler->delegate_.StartEventHandler();
return handler;
}
private:
EventHandlerImplementation delegate_;
};
#endif // BIN_EVENTHANDLER_H_

View file

@ -0,0 +1,327 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include <errno.h>
#include <poll.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
#include "bin/eventhandler.h"
#include "bin/fdutils.h"
int64_t GetCurrentTimeMilliseconds() {
struct timeval tv;
if (gettimeofday(&tv, NULL) < 0) {
UNREACHABLE();
return 0;
}
return ((static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec) / 1000;
}
static const int kInitialPortMapSize = 128;
static const int kPortMapGrowingFactor = 2;
static const int kInterruptMessageSize = sizeof(InterruptMessage);
static const int kInfinityTimeout = -1;
static const int kTimerId = -1;
EventHandlerImplementation::EventHandlerImplementation() {
intptr_t result;
port_map_entries_ = 0;
port_map_size_ = kInitialPortMapSize;
port_map_ = reinterpret_cast<PortData*>(calloc(port_map_size_,
sizeof(PortData)));
ASSERT(port_map_ != NULL);
result = pipe(interrupt_fds_);
if (result != 0) {
FATAL("Pipe creation failed");
}
FDUtils::SetNonBlocking(interrupt_fds_[0]);
FDUtils::SetNonBlocking(interrupt_fds_[1]);
timeout_ = kInfinityTimeout;
timeout_port_ = 0;
}
EventHandlerImplementation::~EventHandlerImplementation() {
free(port_map_);
close(interrupt_fds_[0]);
close(interrupt_fds_[1]);
}
// TODO(hpayer): Use hash table instead of array.
void EventHandlerImplementation::SetPort(intptr_t fd,
Dart_Port dart_port,
intptr_t mask) {
assert(fd >= 0);
if (fd >= port_map_size_) {
intptr_t new_port_map_size = port_map_size_;
do {
new_port_map_size = new_port_map_size * kPortMapGrowingFactor;
} while (fd >= new_port_map_size);
size_t new_port_map_bytes = new_port_map_size * sizeof(PortData);
port_map_ = reinterpret_cast<PortData*>(realloc(port_map_,
new_port_map_bytes));
ASSERT(port_map_ != NULL);
size_t port_map_bytes = port_map_size_ * sizeof(PortData);
memset(port_map_ + port_map_bytes,
0,
new_port_map_bytes - port_map_bytes);
port_map_size_ = new_port_map_size;
}
/*
* Only change the port map entries count if SetPort changes
* the port map state.
*/
if (dart_port == 0 && PortFor(fd) != 0) {
port_map_entries_--;
} else if (dart_port != 0 && PortFor(fd) == 0) {
port_map_entries_++;
}
port_map_[fd].dart_port = dart_port;
port_map_[fd].mask = mask;
}
Dart_Port EventHandlerImplementation::PortFor(intptr_t fd) {
return port_map_[fd].dart_port;
}
void EventHandlerImplementation::RegisterFdWakeup(intptr_t id,
Dart_Port dart_port,
intptr_t data) {
WakeupHandler(id, dart_port, data);
}
void EventHandlerImplementation::CloseFd(intptr_t id) {
SetPort(id, 0, 0);
close(id);
}
void EventHandlerImplementation::UnregisterFdWakeup(intptr_t id) {
WakeupHandler(id, 0, 0);
}
void EventHandlerImplementation::UnregisterFd(intptr_t id) {
SetPort(id, 0, 0);
}
void EventHandlerImplementation::WakeupHandler(intptr_t id,
Dart_Port dart_port,
int64_t data) {
InterruptMessage msg;
msg.id = id;
msg.dart_port = dart_port;
msg.data = data;
intptr_t result =
write(interrupt_fds_[1], &msg, kInterruptMessageSize);
if (result != kInterruptMessageSize) {
perror("Interrupt message failure");
}
}
void EventHandlerImplementation::SetPollEvents(struct pollfd* pollfds,
intptr_t mask) {
/*
* We do not set POLLERR and POLLHUP explicitly since they are triggered
* anyway.
*/
pollfds->events |= POLLRDHUP;
if ((mask & (1 << kInEvent)) != 0) {
pollfds->events |= POLLIN;
}
if ((mask & (1 << kOutEvent)) != 0) {
pollfds->events |= POLLOUT;
}
}
struct pollfd* EventHandlerImplementation::GetPollFds(intptr_t* pollfds_size) {
struct pollfd* pollfds;
intptr_t numPollfds = 1 + port_map_entries_;
pollfds = reinterpret_cast<struct pollfd*>(calloc(sizeof(struct pollfd),
numPollfds));
pollfds[0].fd = interrupt_fds_[0];
pollfds[0].events |= POLLIN;
// TODO(hpayer): optimize the following iteration over the hash map
int j = 1;
for (int i = 0; i < port_map_size_; i++) {
if (port_map_[i].dart_port != 0) {
// Fd is added to the poll set.
pollfds[j].fd = i;
SetPollEvents(&pollfds[j], port_map_[i].mask);
j++;
}
}
*pollfds_size = numPollfds;
return pollfds;
}
bool EventHandlerImplementation::GetInterruptMessage(InterruptMessage* msg) {
int total_read = 0;
int bytes_read = read(interrupt_fds_[0], msg, kInterruptMessageSize);
if (bytes_read < 0) {
return false;
}
total_read = bytes_read;
while (total_read < kInterruptMessageSize) {
bytes_read = read(interrupt_fds_[0],
msg + total_read,
kInterruptMessageSize - total_read);
if (bytes_read > 0) {
total_read = total_read + bytes_read;
}
}
return (total_read == kInterruptMessageSize) ? true : false;
}
void EventHandlerImplementation::HandleInterruptFd() {
InterruptMessage msg;
while (GetInterruptMessage(&msg)) {
if (msg.id == kTimerId) {
timeout_ = msg.data;
timeout_port_ = msg.dart_port;
} else if ((msg.data & (1 << kCloseCommand)) != 0) {
/*
* A close event happened in dart, we have to explicitly unregister
* the fd and close the fd.
*/
CloseFd(msg.id);
} else {
SetPort(msg.id, msg.dart_port, msg.data);
}
}
}
intptr_t EventHandlerImplementation::GetPollEvents(struct pollfd* pollfd) {
intptr_t event_mask = 0;
/*
* We prioritize the events in the following order.
*/
if ((pollfd->revents & POLLIN) != 0) {
if (FDUtils::AvailableBytes(pollfd->fd) != 0) {
event_mask = (1 << kInEvent);
} else if (((pollfd->revents & POLLHUP) != 0) ||
((pollfd->revents & POLLRDHUP) != 0)) {
event_mask = (1 << kCloseEvent);
} else if ((pollfd->revents & POLLERR) != 0) {
event_mask = (1 << kErrorEvent);
} else {
/*
* Accept event.
*/
event_mask = (1 << kInEvent);
}
}
if ((pollfd->revents & POLLOUT) != 0) {
event_mask |= (1 << kOutEvent);
}
return event_mask;
}
void EventHandlerImplementation::HandleEvents(struct pollfd* pollfds,
int pollfds_size,
int result_size) {
if ((pollfds[0].revents & POLLIN) != 0) {
result_size -= 1;
}
if (result_size > 0) {
for (int i = 1; i < pollfds_size; i++) {
/*
* The fd is unregistered. It gets re-registered when the request
* was handled by dart.
*/
intptr_t event_mask = GetPollEvents(&pollfds[i]);
if (event_mask != 0) {
intptr_t fd = pollfds[i].fd;
Dart_Port port = PortFor(fd);
assert(port != 0);
UnregisterFd(fd);
Dart_PostIntArray(port, 1, &event_mask);
}
}
}
HandleInterruptFd();
}
intptr_t EventHandlerImplementation::GetTimeout() {
if (timeout_ == kInfinityTimeout) {
return kInfinityTimeout;
}
intptr_t millis = timeout_ - GetCurrentTimeMilliseconds();
return (millis < 0) ? 0 : millis;
}
void EventHandlerImplementation::HandleTimeout() {
if (timeout_ != kInfinityTimeout) {
intptr_t millis = timeout_ - GetCurrentTimeMilliseconds();
if (millis <= 0) {
Dart_PostIntArray(timeout_port_, 0, NULL);
timeout_ = kInfinityTimeout;
timeout_port_ = 0;
}
}
}
void* EventHandlerImplementation::Poll(void* args) {
intptr_t pollfds_size;
struct pollfd* pollfds;
EventHandlerImplementation* handler =
reinterpret_cast<EventHandlerImplementation*>(args);
while (1) {
pollfds = handler->GetPollFds(&pollfds_size);
intptr_t millis = handler->GetTimeout();
intptr_t result = poll(pollfds, pollfds_size, millis);
if (result == -1) {
perror("Poll failed");
} else {
handler->HandleTimeout();
handler->HandleEvents(pollfds, pollfds_size, result);
}
free(pollfds);
}
return NULL;
}
void EventHandlerImplementation::StartEventHandler() {
pthread_t handler_thread;
int result = pthread_create(&handler_thread,
NULL,
&EventHandlerImplementation::Poll,
this);
if (result != 0) {
FATAL("Create start event handler thread");
}
}
void EventHandlerImplementation::SendData(intptr_t id,
Dart_Port dart_port,
intptr_t data) {
RegisterFdWakeup(id, dart_port, data);
}

View file

@ -0,0 +1,57 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef BIN_EVENTHANDLER_LINUX_H_
#define BIN_EVENTHANDLER_LINUX_H_
typedef struct {
intptr_t id;
Dart_Port dart_port;
int64_t data;
} InterruptMessage;
typedef struct {
Dart_Port dart_port;
intptr_t mask;
} PortData;
class EventHandlerImplementation {
public:
EventHandlerImplementation();
~EventHandlerImplementation();
void SendData(intptr_t id, Dart_Port dart_port, intptr_t data);
void StartEventHandler();
private:
intptr_t GetTimeout();
bool GetInterruptMessage(InterruptMessage* msg);
struct pollfd* GetPollFds(intptr_t* size);
void RegisterFdWakeup(intptr_t id, Dart_Port dart_port, intptr_t data);
void UnregisterFdWakeup(intptr_t id);
void CloseFd(intptr_t id);
void UnregisterFd(intptr_t id);
void HandleEvents(struct pollfd* pollfds, int pollfds_size, int result_size);
void HandleTimeout();
static void* Poll(void* args);
void WakeupHandler(intptr_t id, Dart_Port dart_port, int64_t data);
void HandleInterruptFd();
void SetPort(intptr_t fd, Dart_Port dart_port, intptr_t mask);
Dart_Port PortFor(intptr_t fd);
intptr_t GetPollEvents(struct pollfd* pollfd);
void SetPollEvents(struct pollfd* pollfds, intptr_t mask);
PortData* port_map_;
intptr_t port_map_entries_;
intptr_t port_map_size_;
int64_t timeout_; // Time for next timeout.
Dart_Port timeout_port_;
int interrupt_fds_[2];
};
#endif // BIN_EVENTHANDLER_LINUX_H_

View file

@ -0,0 +1,325 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include <errno.h>
#include <poll.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
#include "bin/eventhandler.h"
#include "bin/fdutils.h"
int64_t GetCurrentTimeMilliseconds() {
struct timeval tv;
if (gettimeofday(&tv, NULL) < 0) {
UNREACHABLE();
return 0;
}
return ((static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec) / 1000;
}
static const int kInitialPortMapSize = 128;
static const int kPortMapGrowingFactor = 2;
static const int kInterruptMessageSize = sizeof(InterruptMessage);
static const int kInfinityTimeout = -1;
static const int kTimerId = -1;
EventHandlerImplementation::EventHandlerImplementation() {
intptr_t result;
port_map_entries_ = 0;
port_map_size_ = kInitialPortMapSize;
port_map_ = reinterpret_cast<PortData*>(calloc(port_map_size_,
sizeof(PortData)));
ASSERT(port_map_ != NULL);
result = pipe(interrupt_fds_);
if (result != 0) {
FATAL("Pipe creation failed");
}
FDUtils::SetNonBlocking(interrupt_fds_[0]);
FDUtils::SetNonBlocking(interrupt_fds_[1]);
timeout_ = kInfinityTimeout;
timeout_port_ = 0;
}
EventHandlerImplementation::~EventHandlerImplementation() {
free(port_map_);
close(interrupt_fds_[0]);
close(interrupt_fds_[1]);
}
// TODO(hpayer): Use hash table instead of array.
void EventHandlerImplementation::SetPort(intptr_t fd,
Dart_Port dart_port,
intptr_t mask) {
assert(fd >= 0);
if (fd >= port_map_size_) {
intptr_t new_port_map_size = port_map_size_;
do {
new_port_map_size = new_port_map_size * kPortMapGrowingFactor;
} while (fd >= new_port_map_size);
size_t new_port_map_bytes = new_port_map_size * sizeof(PortData);
port_map_ = reinterpret_cast<PortData*>(realloc(port_map_,
new_port_map_bytes));
ASSERT(port_map_ != NULL);
size_t port_map_bytes = port_map_size_ * sizeof(PortData);
memset(port_map_ + port_map_bytes,
0,
new_port_map_bytes - port_map_bytes);
port_map_size_ = new_port_map_size;
}
/*
* Only change the port map entries count if SetPort changes
* the port map state.
*/
if (dart_port == 0 && PortFor(fd) != 0) {
port_map_entries_--;
} else if (dart_port != 0 && PortFor(fd) == 0) {
port_map_entries_++;
}
port_map_[fd].dart_port = dart_port;
port_map_[fd].mask = mask;
}
Dart_Port EventHandlerImplementation::PortFor(intptr_t fd) {
return port_map_[fd].dart_port;
}
void EventHandlerImplementation::RegisterFdWakeup(intptr_t id,
Dart_Port dart_port,
intptr_t data) {
WakeupHandler(id, dart_port, data);
}
void EventHandlerImplementation::CloseFd(intptr_t id) {
SetPort(id, 0, 0);
close(id);
}
void EventHandlerImplementation::UnregisterFdWakeup(intptr_t id) {
WakeupHandler(id, 0, 0);
}
void EventHandlerImplementation::UnregisterFd(intptr_t id) {
SetPort(id, 0, 0);
}
void EventHandlerImplementation::WakeupHandler(intptr_t id,
Dart_Port dart_port,
int64_t data) {
InterruptMessage msg;
msg.id = id;
msg.dart_port = dart_port;
msg.data = data;
intptr_t result =
write(interrupt_fds_[1], &msg, kInterruptMessageSize);
if (result != kInterruptMessageSize) {
perror("Interrupt message failure");
}
}
void EventHandlerImplementation::SetPollEvents(struct pollfd* pollfds,
intptr_t mask) {
/*
* We do not set POLLERR and POLLHUP explicitly since they are triggered
* anyway.
*/
if ((mask & (1 << kInEvent)) != 0) {
pollfds->events |= POLLIN;
}
if ((mask & (1 << kOutEvent)) != 0) {
pollfds->events |= POLLOUT;
}
}
struct pollfd* EventHandlerImplementation::GetPollFds(intptr_t* pollfds_size) {
struct pollfd* pollfds;
intptr_t numPollfds = 1 + port_map_entries_;
pollfds = reinterpret_cast<struct pollfd*>(calloc(sizeof(struct pollfd),
numPollfds));
pollfds[0].fd = interrupt_fds_[0];
pollfds[0].events |= POLLIN;
// TODO(hpayer): optimize the following iteration over the hash map
int j = 1;
for (int i = 0; i < port_map_size_; i++) {
if (port_map_[i].dart_port != 0) {
// Fd is added to the poll set.
pollfds[j].fd = i;
SetPollEvents(&pollfds[j], port_map_[i].mask);
j++;
}
}
*pollfds_size = numPollfds;
return pollfds;
}
bool EventHandlerImplementation::GetInterruptMessage(InterruptMessage* msg) {
int total_read = 0;
int bytes_read = read(interrupt_fds_[0], msg, kInterruptMessageSize);
if (bytes_read < 0) {
return false;
}
total_read = bytes_read;
while (total_read < kInterruptMessageSize) {
bytes_read = read(interrupt_fds_[0],
msg + total_read,
kInterruptMessageSize - total_read);
if (bytes_read > 0) {
total_read = total_read + bytes_read;
}
}
return (total_read == kInterruptMessageSize) ? true : false;
}
void EventHandlerImplementation::HandleInterruptFd() {
InterruptMessage msg;
while (GetInterruptMessage(&msg)) {
if (msg.id == kTimerId) {
timeout_ = msg.data;
timeout_port_ = msg.dart_port;
} else if ((msg.data & (1 << kCloseCommand)) != 0) {
/*
* A close event happened in dart, we have to explicitly unregister
* the fd and close the fd.
*/
CloseFd(msg.id);
} else {
SetPort(msg.id, msg.dart_port, msg.data);
}
}
}
intptr_t EventHandlerImplementation::GetPollEvents(struct pollfd* pollfd) {
intptr_t event_mask = 0;
/*
* We prioritize the events in the following order.
*/
if ((pollfd->revents & POLLIN) != 0) {
if (FDUtils::AvailableBytes(pollfd->fd) != 0) {
event_mask = (1 << kInEvent);
} else if ((pollfd->revents & POLLHUP) != 0) {
event_mask = (1 << kCloseEvent);
} else if ((pollfd->revents & POLLERR) != 0) {
event_mask = (1 << kErrorEvent);
} else {
/*
* Accept event.
*/
event_mask = (1 << kInEvent);
}
}
if ((pollfd->revents & POLLOUT) != 0) {
event_mask |= (1 << kOutEvent);
}
return event_mask;
}
void EventHandlerImplementation::HandleEvents(struct pollfd* pollfds,
int pollfds_size,
int result_size) {
if ((pollfds[0].revents & POLLIN) != 0) {
result_size -= 1;
}
if (result_size > 0) {
for (int i = 1; i < pollfds_size; i++) {
/*
* The fd is unregistered. It gets re-registered when the request
* was handled by dart.
*/
intptr_t event_mask = GetPollEvents(&pollfds[i]);
if (event_mask != 0) {
intptr_t fd = pollfds[i].fd;
Dart_Port port = PortFor(fd);
assert(port != 0);
UnregisterFd(fd);
Dart_PostIntArray(port, 1, &event_mask);
}
}
}
HandleInterruptFd();
}
intptr_t EventHandlerImplementation::GetTimeout() {
if (timeout_ == kInfinityTimeout) {
return kInfinityTimeout;
}
intptr_t millis = timeout_ - GetCurrentTimeMilliseconds();
return (millis < 0) ? 0 : millis;
}
void EventHandlerImplementation::HandleTimeout() {
if (timeout_ != kInfinityTimeout) {
intptr_t millis = timeout_ - GetCurrentTimeMilliseconds();
if (millis <= 0) {
Dart_PostIntArray(timeout_port_, 0, NULL);
timeout_ = kInfinityTimeout;
timeout_port_ = 0;
}
}
}
void* EventHandlerImplementation::Poll(void* args) {
intptr_t pollfds_size;
struct pollfd* pollfds;
EventHandlerImplementation* handler =
reinterpret_cast<EventHandlerImplementation*>(args);
while (1) {
pollfds = handler->GetPollFds(&pollfds_size);
intptr_t millis = handler->GetTimeout();
intptr_t result = poll(pollfds, pollfds_size, millis);
if (result == -1) {
perror("Poll failed");
} else {
handler->HandleTimeout();
handler->HandleEvents(pollfds, pollfds_size, result);
}
free(pollfds);
}
return NULL;
}
void EventHandlerImplementation::StartEventHandler() {
pthread_t handler_thread;
int result = pthread_create(&handler_thread,
NULL,
&EventHandlerImplementation::Poll,
this);
if (result != 0) {
FATAL("Create start event handler thread");
}
}
void EventHandlerImplementation::SendData(intptr_t id,
Dart_Port dart_port,
intptr_t data) {
RegisterFdWakeup(id, dart_port, data);
}

View file

@ -0,0 +1,57 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef BIN_EVENTHANDLER_MACOS_H_
#define BIN_EVENTHANDLER_MACOS_H_
typedef struct {
intptr_t id;
Dart_Port dart_port;
int64_t data;
} InterruptMessage;
typedef struct {
Dart_Port dart_port;
intptr_t mask;
} PortData;
class EventHandlerImplementation {
public:
EventHandlerImplementation();
~EventHandlerImplementation();
void SendData(intptr_t id, Dart_Port dart_port, intptr_t data);
void StartEventHandler();
private:
intptr_t GetTimeout();
bool GetInterruptMessage(InterruptMessage* msg);
struct pollfd* GetPollFds(intptr_t* size);
void RegisterFdWakeup(intptr_t id, Dart_Port dart_port, intptr_t data);
void UnregisterFdWakeup(intptr_t id);
void CloseFd(intptr_t id);
void UnregisterFd(intptr_t id);
void HandleEvents(struct pollfd* pollfds, int pollfds_size, int result_size);
void HandleTimeout();
static void* Poll(void* args);
void WakeupHandler(intptr_t id, Dart_Port dart_port, int64_t data);
void HandleInterruptFd();
void SetPort(intptr_t fd, Dart_Port dart_port, intptr_t mask);
Dart_Port PortFor(intptr_t fd);
intptr_t GetPollEvents(struct pollfd* pollfd);
void SetPollEvents(struct pollfd* pollfds, intptr_t mask);
PortData* port_map_;
intptr_t port_map_entries_;
intptr_t port_map_size_;
int64_t timeout_; // Time for next timeout.
Dart_Port timeout_port_;
int interrupt_fds_[2];
};
#endif // BIN_EVENTHANDLER_MACOS_H_

View file

@ -0,0 +1,778 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include <process.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <mswsock.h>
#include "bin/builtin.h"
#include "bin/eventhandler.h"
#include "bin/socket.h"
static const int kInfinityTimeout = -1;
int64_t GetCurrentTimeMilliseconds() {
static const int64_t kTimeEpoc = 116444736000000000LL;
// Although win32 uses 64-bit integers for representing timestamps,
// these are packed into a FILETIME structure. The FILETIME structure
// is just a struct representing a 64-bit integer. The TimeStamp union
// allows access to both a FILETIME and an integer representation of
// the timestamp.
union TimeStamp {
FILETIME ft_;
int64_t t_;
};
TimeStamp time;
GetSystemTimeAsFileTime(&time.ft_);
return (time.t_ - kTimeEpoc) / 10000;
}
IOBuffer* IOBuffer::AllocateBuffer(int buffer_size, Operation operation) {
IOBuffer* buffer = new(buffer_size) IOBuffer(buffer_size, operation);
return buffer;
}
IOBuffer* IOBuffer::AllocateAcceptBuffer(int buffer_size) {
IOBuffer* buffer = AllocateBuffer(buffer_size, kAccept);
return buffer;
}
IOBuffer* IOBuffer::AllocateReadBuffer(int buffer_size) {
return AllocateBuffer(buffer_size, kRead);
}
IOBuffer* IOBuffer::AllocateWriteBuffer(int buffer_size) {
return AllocateBuffer(buffer_size, kWrite);
}
void IOBuffer::DisposeBuffer(IOBuffer* buffer) {
delete buffer;
}
IOBuffer* IOBuffer::GetFromOverlapped(OVERLAPPED* overlapped) {
IOBuffer* buffer = CONTAINING_RECORD(overlapped, IOBuffer, overlapped_);
return buffer;
}
int IOBuffer::Read(void* buffer, int num_bytes) {
if (num_bytes > GetRemainingLength()) {
num_bytes = GetRemainingLength();
}
memcpy(buffer, GetBufferStart() + index_, num_bytes);
index_ += num_bytes;
return num_bytes;
}
int IOBuffer::Write(const void* buffer, int num_bytes) {
ASSERT(num_bytes == buflen_);
memcpy(GetBufferStart(), buffer, num_bytes);
data_length_ = num_bytes;
return num_bytes;
}
int IOBuffer::GetRemainingLength() {
ASSERT(operation_ == kRead);
return data_length_ - index_;
}
Handle::Handle(HANDLE handle)
: handle_(reinterpret_cast<HANDLE>(handle)),
closing_(false),
port_(0),
completion_port_(INVALID_HANDLE_VALUE),
event_handler_(NULL),
data_ready_(NULL),
pending_read_(NULL),
pending_write_(NULL) {
InitializeCriticalSection(&cs_);
}
Handle::Handle(HANDLE handle, Dart_Port port)
: handle_(reinterpret_cast<HANDLE>(handle)),
closing_(false),
port_(port),
completion_port_(INVALID_HANDLE_VALUE),
event_handler_(NULL),
data_ready_(NULL),
pending_read_(NULL),
pending_write_(NULL) {
InitializeCriticalSection(&cs_);
}
Handle::~Handle() {
DeleteCriticalSection(&cs_);
}
void Handle::Lock() {
EnterCriticalSection(&cs_);
}
void Handle::Unlock() {
LeaveCriticalSection(&cs_);
}
bool Handle::CreateCompletionPort(HANDLE completion_port) {
completion_port_ = CreateIoCompletionPort(handle_,
completion_port,
reinterpret_cast<ULONG_PTR>(this),
0);
if (completion_port_ == NULL) {
fprintf(stderr, "Error CreateIoCompletionPort: %d\n", GetLastError());
return false;
}
return true;
}
void Handle::close() {
ScopedLock lock(this);
if (!closing_) {
// Close the socket and set the closing state. This close method can be
// called again if this socket has pending IO operations in flight.
ASSERT(handle_ != INVALID_HANDLE_VALUE);
closing_ = true;
// According to the documentation from Microsoft socket handles should
// not be closed using CloseHandle but using closesocket.
if (is_socket()) {
closesocket(reinterpret_cast<SOCKET>(handle_));
} else {
CloseHandle(handle_);
}
handle_ = INVALID_HANDLE_VALUE;
}
// Perform socket type specific close handling.
AfterClose();
}
bool Handle::HasPendingRead() {
ScopedLock lock(this);
return pending_read_ != NULL;
}
bool Handle::HasPendingWrite() {
ScopedLock lock(this);
return pending_write_ != NULL;
}
void Handle::ReadComplete(IOBuffer* buffer) {
ScopedLock lock(this);
// Currently only one outstanding read at the time.
ASSERT(pending_read_ == buffer);
ASSERT(data_ready_ == NULL);
if (!closing_ && !buffer->IsEmpty()) {
data_ready_ = pending_read_;
} else {
IOBuffer::DisposeBuffer(buffer);
}
pending_read_ = NULL;
}
void Handle::WriteComplete(IOBuffer* buffer) {
ScopedLock lock(this);
// Currently only one outstanding write at the time.
ASSERT(pending_write_ == buffer);
IOBuffer::DisposeBuffer(buffer);
pending_write_ = NULL;
}
bool Handle::IssueRead() {
ScopedLock lock(this);
ASSERT(type_ != kListenSocket);
ASSERT(completion_port_ != INVALID_HANDLE_VALUE);
ASSERT(pending_read_ == NULL);
IOBuffer* buffer = IOBuffer::AllocateReadBuffer(1024);
BOOL ok = ReadFile(handle_,
buffer->GetBufferStart(),
buffer->GetBufferSize(),
NULL,
buffer->GetCleanOverlapped());
if (ok || GetLastError() == ERROR_IO_PENDING) {
// Completing asynchronously.
pending_read_ = buffer;
return true;
}
fprintf(stderr, "ReadFile failed: %d\n", GetLastError());
event_handler_->HandleClosed(this);
IOBuffer::DisposeBuffer(buffer);
return false;
}
bool Handle::IssueWrite() {
ScopedLock lock(this);
ASSERT(type_ != kListenSocket);
ASSERT(completion_port_ != INVALID_HANDLE_VALUE);
ASSERT(pending_write_ != NULL);
ASSERT(pending_write_->operation() == IOBuffer::kWrite);
IOBuffer* buffer = pending_write_;
BOOL ok = WriteFile(handle_,
buffer->GetBufferStart(),
buffer->GetBufferSize(),
NULL,
buffer->GetCleanOverlapped());
if (ok || GetLastError() == ERROR_IO_PENDING) {
// Completing asynchronously.
pending_write_ = buffer;
return true;
}
fprintf(stderr, "WriteFile failed: %d\n", GetLastError());
event_handler_->HandleClosed(this);
IOBuffer::DisposeBuffer(buffer);
return false;
}
bool ListenSocket::LoadAcceptEx() {
// Load the AcceptEx function into memory using WSAIoctl.
// The WSAIoctl function is an extension of the ioctlsocket()
// function that can use overlapped I/O. The function's 3rd
// through 6th parameters are input and output buffers where
// we pass the pointer to our AcceptEx function. This is used
// so that we can call the AcceptEx function directly, rather
// than refer to the Mswsock.lib library.
GUID guid_accept_ex = WSAID_ACCEPTEX;
DWORD bytes;
int status = WSAIoctl(socket(),
SIO_GET_EXTENSION_FUNCTION_POINTER,
&guid_accept_ex,
sizeof(guid_accept_ex),
&AcceptEx_,
sizeof(AcceptEx_),
&bytes,
NULL,
NULL);
if (status == SOCKET_ERROR) {
fprintf(stderr, "Error WSAIoctl failed: %d\n", WSAGetLastError());
return false;
}
return true;
}
bool ListenSocket::IssueAccept() {
ScopedLock lock(this);
// For AcceptEx there needs to be buffer storage for address
// information for two addresses (local and remote address). The
// AcceptEx documentation says: "This value must be at least 16
// bytes more than the maximum address length for the transport
// protocol in use."
static const int kAcceptExAddressAdditionalBytes = 16;
static const int kAcceptExAddressStorageSize =
sizeof(SOCKADDR_STORAGE) + kAcceptExAddressAdditionalBytes;
IOBuffer* buffer =
IOBuffer::AllocateAcceptBuffer(2 * kAcceptExAddressStorageSize);
DWORD received;
BOOL ok;
ok = AcceptEx_(socket(),
buffer->client(),
buffer->GetBufferStart(),
0, // For now don't receive data with accept.
kAcceptExAddressStorageSize,
kAcceptExAddressStorageSize,
&received,
buffer->GetCleanOverlapped());
if (!ok) {
if (WSAGetLastError() != WSA_IO_PENDING) {
fprintf(stderr, "AcceptEx failed: %d\n", WSAGetLastError());
closesocket(buffer->client());
IOBuffer::DisposeBuffer(buffer);
return false;
}
}
pending_accept_count_++;
return true;
}
void ListenSocket::AcceptComplete(IOBuffer* buffer, HANDLE completion_port) {
ScopedLock lock(this);
if (!closing_) {
ClientSocket* client_socket = new ClientSocket(buffer->client(), 0);
client_socket->CreateCompletionPort(completion_port);
if (accepted_head_ == NULL) {
accepted_head_ = client_socket;
accepted_tail_ = client_socket;
} else {
ASSERT(accepted_tail_ != NULL);
accepted_tail_->set_next(client_socket);
accepted_tail_ = client_socket;
}
} else {
closesocket(buffer->client());
}
pending_accept_count_--;
IOBuffer::DisposeBuffer(buffer);
}
ClientSocket* ListenSocket::Accept() {
ScopedLock lock(this);
if (accepted_head_ == NULL) return NULL;
ClientSocket* result = accepted_head_;
accepted_head_ = accepted_head_->next();
if (accepted_head_ == NULL) accepted_tail_ = NULL;
return result;
}
void ListenSocket::EnsureInitialized(
EventHandlerImplementation* event_handler) {
ScopedLock lock(this);
if (AcceptEx_ == NULL) {
ASSERT(completion_port_ == INVALID_HANDLE_VALUE);
ASSERT(event_handler_ == NULL);
event_handler_ = event_handler;
CreateCompletionPort(event_handler_->completion_port());
LoadAcceptEx();
}
}
void ListenSocket::AfterClose() {
ScopedLock lock(this);
while (true) {
// Get rid of connections already accepted.
ClientSocket *client = Accept();
if (client != NULL) {
client->close();
} else {
break;
}
}
}
bool ListenSocket::IsClosed() {
return closing_ && !HasPendingAccept();
}
int ClientSocket::Available() {
ScopedLock lock(this);
if (data_ready_ == NULL) return 0;
ASSERT(!data_ready_->IsEmpty());
return data_ready_->GetRemainingLength();
}
int ClientSocket::Read(void* buffer, int num_bytes) {
ScopedLock lock(this);
if (data_ready_ == NULL) return 0;
num_bytes = data_ready_->Read(buffer, num_bytes);
if (data_ready_->IsEmpty()) {
IOBuffer::DisposeBuffer(data_ready_);
data_ready_ = NULL;
}
return num_bytes;
}
int ClientSocket::Write(const void* buffer, int num_bytes) {
ScopedLock lock(this);
if (pending_write_ != NULL) return 0;
if (completion_port_ == INVALID_HANDLE_VALUE) return 0;
if (num_bytes > 4096) num_bytes = 4096;
pending_write_ = IOBuffer::AllocateWriteBuffer(num_bytes);
pending_write_->Write(buffer, num_bytes);
IssueWrite();
return num_bytes;
}
bool ClientSocket::IssueRead() {
ScopedLock lock(this);
ASSERT(completion_port_ != INVALID_HANDLE_VALUE);
ASSERT(pending_read_ == NULL);
IOBuffer* buffer = IOBuffer::AllocateReadBuffer(1024);
DWORD flags;
flags = 0;
int rc = WSARecv(socket(),
buffer->GetWASBUF(),
1,
NULL,
&flags,
buffer->GetCleanOverlapped(),
NULL);
if (rc == NO_ERROR || WSAGetLastError() == WSA_IO_PENDING) {
pending_read_ = buffer;
return true;
}
if (WSAGetLastError() != WSAECONNRESET) {
fprintf(stderr, "WSARecv failed: %d\n", WSAGetLastError());
}
event_handler_->HandleClosed(this);
IOBuffer::DisposeBuffer(buffer);
return false;
}
bool ClientSocket::IssueWrite() {
ScopedLock lock(this);
ASSERT(completion_port_ != INVALID_HANDLE_VALUE);
ASSERT(pending_write_ != NULL);
ASSERT(pending_write_->operation() == IOBuffer::kWrite);
int rc = WSASend(socket(),
pending_write_->GetWASBUF(),
1,
NULL,
0,
pending_write_->GetCleanOverlapped(),
NULL);
if (rc == NO_ERROR || WSAGetLastError() == WSA_IO_PENDING) {
return true;
}
fprintf(stderr, "WSASend failed: %d\n", WSAGetLastError());
IOBuffer::DisposeBuffer(pending_write_);
pending_write_ = NULL;
return false;
}
void ClientSocket::EnsureInitialized(
EventHandlerImplementation* event_handler) {
ScopedLock lock(this);
if (completion_port_ == INVALID_HANDLE_VALUE) {
ASSERT(event_handler_ == NULL);
event_handler_ = event_handler;
CreateCompletionPort(event_handler_->completion_port());
}
}
void ClientSocket::AfterClose() {
ScopedLock lock(this);
if (data_ready_ != NULL) {
IOBuffer::DisposeBuffer(data_ready_);
data_ready_ = NULL;
}
}
bool ClientSocket::IsClosed() {
return closing_ && !HasPendingRead() && !HasPendingWrite();
}
void EventHandlerImplementation::HandleInterrupt(InterruptMessage* msg) {
if (msg->id == -1) {
// Change of timeout request. Just set the new timeout and port as the
// completion thread will use the new timeout value for its next wait.
timeout_ = msg->data;
timeout_port_ = msg->dart_port;
} else {
bool delete_socket = false;
Handle* socket_desc =
reinterpret_cast<Handle*>(msg->id);
ASSERT(socket_desc != NULL);
if (socket_desc->is_listen_socket()) {
ListenSocket* listen_socket =
reinterpret_cast<ListenSocket*>(socket_desc);
listen_socket->EnsureInitialized(this);
listen_socket->SetPortAndMask(msg->dart_port, msg->data);
Handle::ScopedLock lock(listen_socket);
// If incomming connections are requested make sure that pending accepts
// are issued.
if ((msg->data & (1 << kInEvent)) != 0) {
while (listen_socket->pending_accept_count() < 5) {
listen_socket->IssueAccept();
}
}
if ((msg->data & (1 << kCloseCommand)) != 0) {
listen_socket->close();
if (listen_socket->IsClosed()) {
delete_socket = true;
}
}
} else {
ClientSocket* client_socket =
reinterpret_cast<ClientSocket*>(socket_desc);
client_socket->SetPortAndMask(msg->dart_port, msg->data);
client_socket->EnsureInitialized(this);
Handle::ScopedLock lock(client_socket);
// If data available callback has been requested and data are
// available post it immediately. Otherwise make sure that a pending
// read is issued.
if ((msg->data & (1 << kInEvent)) != 0) {
if (client_socket->Available() > 0) {
int event_mask = (1 << kInEvent);
Dart_PostIntArray(client_socket->port(), 1, &event_mask);
} else if (!client_socket->HasPendingRead()) {
client_socket->IssueRead();
}
}
// If can send callback had been requested and there is no pending
// send post it immediately.
if ((msg->data & (1 << kOutEvent)) != 0) {
if (!client_socket->HasPendingWrite()) {
int event_mask = (1 << kOutEvent);
Dart_PostIntArray(client_socket->port(), 1, &event_mask);
}
}
if ((msg->data & (1 << kCloseCommand)) != 0) {
client_socket->close();
if (client_socket->IsClosed()) {
delete_socket = true;
}
}
}
if (delete_socket) {
delete socket_desc;
}
}
}
void EventHandlerImplementation::HandleAccept(ListenSocket* listen_socket,
IOBuffer* buffer) {
listen_socket->AcceptComplete(buffer, completion_port_);
if (!listen_socket->is_closing()) {
int event_mask = 1 << kInEvent;
if ((listen_socket->mask() & event_mask) != 0) {
Dart_PostIntArray(listen_socket->port(), 1, &event_mask);
}
}
if (listen_socket->IsClosed()) {
delete listen_socket;
}
}
void EventHandlerImplementation::HandleClosed(Handle* handle) {
if (!handle->is_closing()) {
int event_mask = 1 << kCloseEvent;
if ((handle->mask() & event_mask) != 0) {
Dart_PostIntArray(handle->port(), 1, &event_mask);
}
}
}
void EventHandlerImplementation::HandleRead(ClientSocket* client_socket,
int bytes,
IOBuffer* buffer) {
buffer->set_data_length(bytes);
client_socket->ReadComplete(buffer);
if (bytes > 0) {
if (!client_socket->is_closing()) {
int event_mask = 1 << kInEvent;
if ((client_socket->mask() & event_mask) != 0) {
Dart_PostIntArray(client_socket->port(), 1, &event_mask);
}
}
} else {
ASSERT(bytes == 0);
HandleClosed(client_socket);
}
if (client_socket->IsClosed()) {
delete client_socket;
}
}
void EventHandlerImplementation::HandleWrite(ClientSocket* client_socket,
int bytes,
IOBuffer* buffer) {
client_socket->WriteComplete(buffer);
if (bytes > 0) {
if (!client_socket->is_closing()) {
int event_mask = 1 << kOutEvent;
if ((client_socket->mask() & event_mask) != 0) {
Dart_PostIntArray(client_socket->port(), 1, &event_mask);
}
}
} else {
ASSERT(bytes == 0);
HandleClosed(client_socket);
}
if (client_socket->IsClosed()) {
delete client_socket;
}
}
void EventHandlerImplementation::HandleTimeout() {
// TODO(sgjesse) check if there actually is a timeout.
Dart_PostIntArray(timeout_port_, 0, NULL);
timeout_ = kInfinityTimeout;
timeout_port_ = 0;
}
void EventHandlerImplementation::HandleIOCompletion(DWORD bytes,
ULONG_PTR key,
OVERLAPPED* overlapped) {
IOBuffer* buffer = IOBuffer::GetFromOverlapped(overlapped);
switch (buffer->operation()) {
case IOBuffer::kAccept: {
ListenSocket* listen_socket = reinterpret_cast<ListenSocket*>(key);
HandleAccept(listen_socket, buffer);
break;
}
case IOBuffer::kRead: {
ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(key);
HandleRead(client_socket, bytes, buffer);
break;
}
case IOBuffer::kWrite: {
ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(key);
HandleWrite(client_socket, bytes, buffer);
break;
}
default:
UNREACHABLE();
}
}
EventHandlerImplementation::EventHandlerImplementation() {
intptr_t result;
completion_port_ =
CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1);
if (completion_port_ == NULL) {
FATAL("Completion port creation failed");
}
timeout_ = kInfinityTimeout;
timeout_port_ = 0;
}
DWORD EventHandlerImplementation::GetTimeout() {
if (timeout_ == kInfinityTimeout) {
return kInfinityTimeout;
}
intptr_t millis = timeout_ - GetCurrentTimeMilliseconds();
return (millis < 0) ? 0 : millis;
}
void EventHandlerImplementation::SendData(intptr_t id,
Dart_Port dart_port,
intptr_t data) {
InterruptMessage* msg = new InterruptMessage;
msg->id = id;
msg->dart_port = dart_port;
msg->data = data;
BOOL ok = PostQueuedCompletionStatus(
completion_port_, 0, NULL, reinterpret_cast<OVERLAPPED*>(msg));
if (!ok) {
FATAL("PostQueuedCompletionStatus failed");
}
}
static unsigned int __stdcall EventHandlerThread(void* args) {
EventHandlerImplementation* handler =
reinterpret_cast<EventHandlerImplementation*>(args);
while (true) {
DWORD bytes;
ULONG_PTR key;
OVERLAPPED* overlapped;
intptr_t millis = handler->GetTimeout();
BOOL ok = GetQueuedCompletionStatus(handler->completion_port(),
&bytes,
&key,
&overlapped,
millis);
if (!ok && overlapped == NULL) {
if (GetLastError() == ERROR_ABANDONED_WAIT_0) {
// The completion port should never be closed.
printf("Completion port closed\n");
UNREACHABLE();
} else {
// Timeout is signalled by false result and NULL in overlapped.
handler->HandleTimeout();
}
} else if (!ok) {
// If GetQueuedCompletionStatus return false and overlapped is
// not NULL then it did dequeue a request which failed.
if (overlapped != NULL) {
// Treat ERROR_CONNECTION_ABORTED as connection closed.
// The error ERROR_OPERATION_ABORTED is set for pending
// accept requests for a listen socket which is closed.
if (GetLastError() == ERROR_CONNECTION_ABORTED ||
GetLastError() == ERROR_OPERATION_ABORTED) {
ASSERT(bytes == 0);
handler->HandleIOCompletion(bytes, key, overlapped);
} else {
printf("After GetQueuedCompletionStatus %d\n", GetLastError());
UNREACHABLE();
}
} else {
printf("After GetQueuedCompletionStatus %d\n", GetLastError());
UNREACHABLE();
}
} else if (key == NULL) {
// A key of NULL signals an interrupt message.
InterruptMessage* msg = reinterpret_cast<InterruptMessage*>(overlapped);
handler->HandleInterrupt(msg);
delete msg;
} else {
handler->HandleIOCompletion(bytes, key, overlapped);
}
}
}
void EventHandlerImplementation::StartEventHandler() {
uint32_t tid;
uintptr_t thread_handle =
_beginthreadex(NULL, 32 * 1024, EventHandlerThread, this, 0, &tid);
if (thread_handle == -1) {
FATAL("Failed to start event handler thread");
}
// Initialize Winsock32
if (!Socket::Initialize()) {
FATAL("Failed to initialized Windows sockets");
}
}

View file

@ -0,0 +1,333 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef BIN_EVENTHANDLER_WIN_H_
#define BIN_EVENTHANDLER_WIN_H_
#include <winsock2.h>
#include <mswsock.h>
#include "bin/builtin.h"
// Forward declarations.
class EventHandlerImplementation;
class Handle;
class FileHandle;
class SocketHandle;
class ClientSocket;
class ListenSocket;
struct InterruptMessage {
intptr_t id;
Dart_Port dart_port;
int64_t data;
};
// An IOBuffer encapsulates the OVERLAPPED structure and the
// associated data buffer. For accept it also contains the pre-created
// socket for the client.
class IOBuffer {
public:
enum Operation { kAccept, kRead, kWrite };
static IOBuffer* AllocateAcceptBuffer(int buffer_size);
static IOBuffer* AllocateReadBuffer(int buffer_size);
static IOBuffer* AllocateWriteBuffer(int buffer_size);
static void DisposeBuffer(IOBuffer* buffer);
// Find the IO buffer from the OVERLAPPED address.
static IOBuffer* GetFromOverlapped(OVERLAPPED* overlapped);
// Read data from a buffer which has been received. It will read up
// to num_bytes bytes of data returning the actual number of bytes
// read. This will update the index of the next byte in the buffer
// so calling Read several times will keep returning new data from
// the buffer until all data have been read.
int Read(void* buffer, int num_bytes);
// Write data to a buffer before sending it. Returns the number of bytes
// actually written to the buffer. Calls to Write will always write to
// the buffer from the begining.
int Write(const void* buffer, int num_bytes);
// Check the amount of data in a read buffer which has not been read yet.
int GetRemainingLength();
bool IsEmpty() { return GetRemainingLength() == 0; }
Operation operation() { return operation_; }
SOCKET client() { return client_; }
char* GetBufferStart() { return reinterpret_cast<char*>(&buffer_data_); }
int GetBufferSize() { return buflen_; }
// Returns the address of the OVERLAPPED structure with all fields
// initialized to zero.
OVERLAPPED* GetCleanOverlapped() {
memset(&overlapped_, 0, sizeof(overlapped_));
return &overlapped_;
}
// Returns a WASBUF structure initialized with the data in this IO buffer.
WSABUF* GetWASBUF() {
wbuf_.buf = GetBufferStart();
wbuf_.len = GetBufferSize();
return &wbuf_;
};
void set_data_length(int data_length) { data_length_ = data_length; }
private:
IOBuffer(int buffer_size, Operation operation)
: operation_(operation), buflen_(buffer_size) {
memset(GetBufferStart(), 0, GetBufferSize());
index_ = 0;
data_length_ = 0;
if (operation_ == kAccept) {
client_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
}
}
void* operator new(size_t size, int buffer_size) {
return malloc(size + buffer_size);
}
void operator delete(void* buffer) {
free(buffer);
}
static IOBuffer* AllocateBuffer(int buffer_size, Operation operation);
OVERLAPPED overlapped_; // OVERLAPPED structure for overlapped IO.
SOCKET client_; // Used for AcceptEx client socket.
int buflen_; // Length of the buffer.
Operation operation_; // Type of operation issued.
int index_; // Index for next read from read buffer.
int data_length_; // Length of the actual data in the buffer.
WSABUF wbuf_; // Structure for passing buffer to WSA functions.
// Buffer for recv/send/AcceptEx. This must be at the end of the
// object as the object is allocated larger than it's definition
// indicate to extend this array.
uint8_t buffer_data_[1];
};
// Abstract super class for holding information on listen and connected
// sockets.
class Handle {
public:
enum Type { kFile, kClientSocket, kListenSocket };
class ScopedLock {
public:
explicit ScopedLock(Handle* handle)
: handle_(handle) {
handle_->Lock();
}
~ScopedLock() {
handle_->Unlock();
}
private:
Handle* handle_;
};
virtual ~Handle();
// Internal interface used by the event handler.
virtual bool IssueRead();
virtual bool IssueWrite();
bool HasPendingRead();
bool HasPendingWrite();
void ReadComplete(IOBuffer* buffer);
void WriteComplete(IOBuffer* buffer);
virtual void EnsureInitialized(
EventHandlerImplementation* event_handler) = 0;
HANDLE handle() { return handle_; }
Dart_Port port() { return port_; }
EventHandlerImplementation* event_handler() { return event_handler_; }
void Lock();
void Unlock();
bool CreateCompletionPort(HANDLE completion_port);
void close();
virtual bool IsClosed() = 0;
void SetPortAndMask(Dart_Port port, intptr_t mask) {
port_ = port;
mask_ = mask;
}
Type type() { return type_; }
bool is_file() { return type_ == kFile; }
bool is_socket() { return type_ == kListenSocket || type_ == kClientSocket; }
bool is_listen_socket() { return type_ == kListenSocket; }
bool is_client_socket() { return type_ == kClientSocket; }
intptr_t mask() { return mask_; }
bool is_closing() { return closing_; }
protected:
explicit Handle(HANDLE handle);
Handle(HANDLE handle, Dart_Port port);
virtual void AfterClose() = 0;
Type type_;
HANDLE handle_;
bool closing_; // Is this handle in the process of closing?
Dart_Port port_; // Dart port to communicate events for this socket.
intptr_t mask_; // Mask of events to report through the port.
HANDLE completion_port_;
CRITICAL_SECTION cs_; // Critical section protecting this object.
EventHandlerImplementation* event_handler_;
IOBuffer* data_ready_; // IO buffer for data ready to be read.
IOBuffer* pending_read_; // IO buffer for pending read.
IOBuffer* pending_write_; // IO buffer for pending write
};
class FileHandle : public Handle {
public:
explicit FileHandle(HANDLE handle)
: Handle(reinterpret_cast<HANDLE>(handle)) { type_ = kFile; }
FileHandle(HANDLE handle, Dart_Port port)
: Handle(reinterpret_cast<HANDLE>(handle), port) { type_ = kFile; }
};
class SocketHandle : public Handle {
public:
SOCKET socket() { return reinterpret_cast<SOCKET>(handle_); }
protected:
explicit SocketHandle(SOCKET s) : Handle(reinterpret_cast<HANDLE>(s)) {}
SocketHandle(SOCKET s, Dart_Port port)
: Handle(reinterpret_cast<HANDLE>(s), port) {}
};
// Information on listen sockets.
class ListenSocket : public SocketHandle {
public:
explicit ListenSocket(SOCKET s) : SocketHandle(s),
AcceptEx_(NULL),
pending_accept_count_(0),
accepted_head_(NULL),
accepted_tail_(NULL) {
type_ = kListenSocket;
}
virtual ~ListenSocket() {
ASSERT(!HasPendingAccept());
ASSERT(accepted_head_ == NULL);
ASSERT(accepted_tail_ == NULL);
};
// Socket interface exposing normal socket operations.
ClientSocket* Accept();
// Internal interface used by the event handler.
bool HasPendingAccept() { return pending_accept_count_ > 0; }
bool IssueAccept();
void AcceptComplete(IOBuffer* buffer, HANDLE completion_port);
virtual void EnsureInitialized(
EventHandlerImplementation* event_handler);
virtual bool IsClosed();
int pending_accept_count() { return pending_accept_count_; }
private:
bool LoadAcceptEx();
virtual void AfterClose();
LPFN_ACCEPTEX AcceptEx_;
int pending_accept_count_;
// Linked list of accepted connections provided by completion code. Ready to
// be handed over through accept.
ClientSocket* accepted_head_;
ClientSocket* accepted_tail_;
};
// Information on connected sockets.
class ClientSocket : public SocketHandle {
public:
explicit ClientSocket(SOCKET s)
: SocketHandle(s),
next_(NULL) { type_ = kClientSocket; }
ClientSocket(SOCKET s, Dart_Port port)
: SocketHandle(s, port),
next_(NULL) { type_ = kClientSocket; }
virtual ~ClientSocket() {
// Don't delete this object until all pending requests have been handled.
ASSERT(!HasPendingRead());
ASSERT(!HasPendingWrite());
ASSERT(next_ == NULL);
};
// Socket interface exposing normal socket operations.
int Available();
int Read(void* buffer, int num_bytes);
int Write(const void* buffer, int num_bytes);
// Internal interface used by the event handler.
virtual bool IssueRead();
virtual bool IssueWrite();
virtual void EnsureInitialized(
EventHandlerImplementation* event_handler);
virtual bool IsClosed();
ClientSocket* next() { return next_; }
void set_next(ClientSocket* next) { next_ = next; }
private:
virtual void AfterClose();
ClientSocket* next_;
};
// Event handler.
class EventHandlerImplementation {
public:
EventHandlerImplementation();
virtual ~EventHandlerImplementation() {}
void SendData(intptr_t id, Dart_Port dart_port, intptr_t data);
void StartEventHandler();
DWORD GetTimeout();
void HandleInterrupt(InterruptMessage* msg);
void HandleTimeout();
void HandleAccept(ListenSocket* listen_socket, IOBuffer* buffer);
void HandleClosed(Handle* handle);
void HandleRead(ClientSocket* client_socket, int bytes, IOBuffer* buffer);
void HandleWrite(ClientSocket* client_socket, int bytes, IOBuffer* buffer);
void HandleClose(ClientSocket* client_socket);
void HandleIOCompletion(DWORD bytes, ULONG_PTR key, OVERLAPPED* overlapped);
HANDLE completion_port() { return completion_port_; }
private:
ClientSocket* client_sockets_head_;
int64_t timeout_; // Time for next timeout.
Dart_Port timeout_port_;
HANDLE completion_port_;
};
#endif // BIN_EVENTHANDLER_WIN_H_

41
runtime/bin/fdutils.h Normal file
View file

@ -0,0 +1,41 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef BIN_FDUTILS_H_
#define BIN_FDUTILS_H_
#include "bin/builtin.h"
#include "bin/globals.h"
class FDUtils {
public:
static bool SetNonBlocking(intptr_t fd);
// Checks whether the file descriptor is blocking. If the function
// returns true the value pointed to by is_blocking will be set to
// the blocking state of the file descriptor. If the function
// returns false the system call for checking the file descriptor
// failed and the value pointed to by is_blocking is not modified.
static bool IsBlocking(intptr_t fd, bool* is_blocking);
static intptr_t AvailableBytes(intptr_t fd);
// Reads the requested number of bytes from a file descriptor. This
// function will only return on short reads if an error occours in
// which case it returns -1 and errno is still valid. The file
// descriptor must be in blocking mode.
static ssize_t ReadFromBlocking(int fd, void* buffer, size_t count);
// Writes the requested number of bytes to a file descriptor. This
// function will only return on short writes if an error occours in
// which case it returns -1 and errno is still valid. The file
// descriptor must be in blocking mode.
static ssize_t WriteToBlocking(int fd, const void* buffer, size_t count);
private:
DISALLOW_ALLOCATION();
DISALLOW_IMPLICIT_CONSTRUCTORS(FDUtils);
};
#endif // BIN_FDUTILS_H_

View file

@ -0,0 +1,104 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include "bin/fdutils.h"
bool FDUtils::SetNonBlocking(intptr_t fd) {
intptr_t status;
status = fcntl(fd, F_GETFL);
if (status < 0) {
perror("fcntl F_GETFL failed");
return false;
}
status = (status | O_NONBLOCK);
if (fcntl(fd, F_SETFL, status) < 0) {
perror("fcntl F_SETFL failed");
return false;
}
return true;
}
bool FDUtils::IsBlocking(intptr_t fd, bool* is_blocking) {
intptr_t status;
status = fcntl(fd, F_GETFL);
if (status < 0) {
perror("fcntl F_GETFL failed");
return false;
}
*is_blocking = (status & O_NONBLOCK) == 0;
return true;
}
intptr_t FDUtils::AvailableBytes(intptr_t fd) {
size_t available;
int result = ioctl(fd, FIONREAD, &available);
if (result < 0) {
return result;
}
return available;
}
ssize_t FDUtils::ReadFromBlocking(int fd, void* buffer, size_t count) {
#ifdef DEBUG
bool is_blocking = false;
ASSERT(FDUtils::IsBlocking(fd, &is_blocking));
ASSERT(is_blocking);
#endif
size_t remaining = count;
char* buffer_pos = reinterpret_cast<char*>(buffer);
while (remaining > 0) {
ssize_t bytes_read = read(fd, buffer_pos, remaining);
if (bytes_read == 0) {
return count - remaining;
} else if (bytes_read == -1 && errno != EINTR) {
// Error codes EAGAIN and EWOULDBLOCK should only happen for non
// blocking file descriptors.
ASSERT(errno != EAGAIN && errno != EWOULDBLOCK);
return -1;
} else if (bytes_read > 0) {
remaining -= bytes_read;
buffer_pos += bytes_read;
} else {
ASSERT(errno == EINTR);
}
}
return count;
}
ssize_t FDUtils::WriteToBlocking(int fd, const void* buffer, size_t count) {
#ifdef DEBUG
bool is_blocking = false;
ASSERT(FDUtils::IsBlocking(fd, &is_blocking));
ASSERT(is_blocking);
#endif
size_t remaining = count;
char* buffer_pos = const_cast<char*>(reinterpret_cast<const char*>(buffer));
while (remaining > 0) {
ssize_t bytes_written = write(fd, buffer_pos, remaining);
if (bytes_written == 0) {
return count - remaining;
} else if (bytes_written == -1 && errno != EINTR) {
// Error codes EAGAIN and EWOULDBLOCK should only happen for non
// blocking file descriptors.
ASSERT(errno != EAGAIN && errno != EWOULDBLOCK);
return -1;
} else if (bytes_written > 0) {
remaining -= bytes_written;
buffer_pos += bytes_written;
} else {
ASSERT(errno == EINTR);
}
}
return count;
}

View file

@ -0,0 +1,104 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include "bin/fdutils.h"
bool FDUtils::SetNonBlocking(intptr_t fd) {
intptr_t status;
status = fcntl(fd, F_GETFL);
if (status < 0) {
perror("fcntl F_GETFL failed");
return false;
}
status = (status | O_NONBLOCK);
if (fcntl(fd, F_SETFL, status) < 0) {
perror("fcntl F_SETFL failed");
return false;
}
return true;
}
bool FDUtils::IsBlocking(intptr_t fd, bool* is_blocking) {
intptr_t status;
status = fcntl(fd, F_GETFL);
if (status < 0) {
perror("fcntl F_GETFL failed");
return false;
}
*is_blocking = (status & O_NONBLOCK) == 0;
return true;
}
intptr_t FDUtils::AvailableBytes(intptr_t fd) {
size_t available;
int result = ioctl(fd, FIONREAD, &available);
if (result < 0) {
return result;
}
return available;
}
ssize_t FDUtils::ReadFromBlocking(int fd, void* buffer, size_t count) {
#ifdef DEBUG
bool is_blocking = false;
ASSERT(FDUtils::IsBlocking(fd, &is_blocking));
ASSERT(is_blocking);
#endif
size_t remaining = count;
char* buffer_pos = reinterpret_cast<char*>(buffer);
while (remaining > 0) {
ssize_t bytes_read = read(fd, buffer_pos, remaining);
if (bytes_read == 0) {
return count - remaining;
} else if (bytes_read == -1 && errno != EINTR) {
// Error codes EAGAIN and EWOULDBLOCK should only happen for non
// blocking file descriptors.
ASSERT(errno != EAGAIN && errno != EWOULDBLOCK);
return -1;
} else if (bytes_read > 0) {
remaining -= bytes_read;
buffer_pos += bytes_read;
} else {
ASSERT(errno == EINTR);
}
}
return count;
}
ssize_t FDUtils::WriteToBlocking(int fd, const void* buffer, size_t count) {
#ifdef DEBUG
bool is_blocking = false;
ASSERT(FDUtils::IsBlocking(fd, &is_blocking));
ASSERT(is_blocking);
#endif
size_t remaining = count;
char* buffer_pos = const_cast<char*>(reinterpret_cast<const char*>(buffer));
while (remaining > 0) {
ssize_t bytes_written = write(fd, buffer_pos, remaining);
if (bytes_written == 0) {
return count - remaining;
} else if (bytes_written == -1 && errno != EINTR) {
// Error codes EAGAIN and EWOULDBLOCK should only happen for non
// blocking file descriptors.
ASSERT(errno != EAGAIN && errno != EWOULDBLOCK);
return -1;
} else if (bytes_written > 0) {
remaining -= bytes_written;
buffer_pos += bytes_written;
} else {
ASSERT(errno == EINTR);
}
}
return count;
}

243
runtime/bin/file.cc Normal file
View file

@ -0,0 +1,243 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "bin/file.h"
#include "bin/builtin.h"
#include "bin/dartutils.h"
#include "include/dart_api.h"
static const int kFileFieldIndex = 0;
bool File::ReadFully(void* buffer, int64_t num_bytes) {
int64_t remaining = num_bytes;
char* current_buffer = reinterpret_cast<char*>(buffer);
while (remaining > 0) {
int bytes_read = Read(current_buffer, remaining);
if (bytes_read <= 0) {
return false;
}
remaining -= bytes_read; // Reduce the number of remaining bytes.
current_buffer += bytes_read; // Move the buffer forward.
}
return true;
}
bool File::WriteFully(const void* buffer, int64_t num_bytes) {
int64_t remaining = num_bytes;
const char* current_buffer = reinterpret_cast<const char*>(buffer);
while (remaining > 0) {
int bytes_read = Write(current_buffer, remaining);
if (bytes_read < 0) {
return false;
}
remaining -= bytes_read; // Reduce the number of remaining bytes.
current_buffer += bytes_read; // Move the buffer forward.
}
return true;
}
static File* GetFileHandle(Dart_Handle fileobj) {
Dart_Result result = Dart_GetNativeInstanceField(fileobj, kFileFieldIndex);
assert(Dart_IsValidResult(result));
File* file = reinterpret_cast<File*>(Dart_GetResultAsCIntptr(result));
return file;
}
void FUNCTION_NAME(File_OpenFile)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle fileobj = Dart_GetNativeArgument(args, 0);
const char* filename =
DartUtils::GetStringValue(Dart_GetNativeArgument(args, 1));
bool writable = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 2));
File* file = File::OpenFile(filename, writable);
Dart_SetNativeInstanceField(fileobj,
kFileFieldIndex,
reinterpret_cast<intptr_t>(file));
Dart_SetReturnValue(args, Dart_NewBoolean(file != NULL));
Dart_ExitScope();
}
void FUNCTION_NAME(File_Exists)(Dart_NativeArguments args) {
Dart_EnterScope();
const char* filename =
DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0));
bool exists = File::FileExists(filename);
Dart_SetReturnValue(args, Dart_NewBoolean(exists));
Dart_ExitScope();
}
void FUNCTION_NAME(File_Close)(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t return_value = -1;
Dart_Handle fileobj = Dart_GetNativeArgument(args, 0);
File* file = GetFileHandle(fileobj);
if (file != NULL) {
Dart_SetNativeInstanceField(fileobj,
kFileFieldIndex,
NULL);
delete file;
return_value = 0;
}
Dart_SetReturnValue(args, Dart_NewInteger(return_value));
Dart_ExitScope();
}
void FUNCTION_NAME(File_ReadByte)(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t return_value = -1;
File* file = GetFileHandle(Dart_GetNativeArgument(args, 0));
if (file != NULL) {
uint8_t buffer;
int bytes_read = file->Read(reinterpret_cast<void*>(&buffer), 1);
if (bytes_read >= 0) {
return_value = static_cast<intptr_t>(buffer);
}
}
Dart_SetReturnValue(args, Dart_NewInteger(return_value));
Dart_ExitScope();
}
void FUNCTION_NAME(File_WriteByte)(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t return_value = -1;
File* file = GetFileHandle(Dart_GetNativeArgument(args, 0));
if (file != NULL) {
int64_t value = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 1));
uint8_t buffer = static_cast<uint8_t>(value & 0xff);
int bytes_written = file->Write(reinterpret_cast<void*>(&buffer), 1);
if (bytes_written >= 0) {
return_value = bytes_written;
}
}
Dart_SetReturnValue(args, Dart_NewInteger(return_value));
Dart_ExitScope();
}
void FUNCTION_NAME(File_WriteString)(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t return_value = -1;
File* file = GetFileHandle(Dart_GetNativeArgument(args, 0));
if (file != NULL) {
const char* str =
DartUtils::GetStringValue(Dart_GetNativeArgument(args, 1));
int bytes_written = file->Write(reinterpret_cast<const void*>(str),
strlen(str));
if (bytes_written >= 0) {
return_value = bytes_written;
}
}
Dart_SetReturnValue(args, Dart_NewInteger(return_value));
Dart_ExitScope();
}
void FUNCTION_NAME(File_ReadList)(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t return_value = -1;
File* file = GetFileHandle(Dart_GetNativeArgument(args, 0));
if (file != NULL) {
Dart_Handle buffer_obj = Dart_GetNativeArgument(args, 1);
assert(Dart_IsArray(buffer_obj));
int64_t offset =
DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 2));
int64_t length =
DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 3));
Dart_Result result = Dart_GetLength(buffer_obj);
assert(Dart_IsValidResult(result));
assert((offset + length) <= Dart_GetResultAsCIntptr(result));
uint8_t* buffer = new uint8_t[length];
int total_bytes_read =
file->Read(reinterpret_cast<void*>(buffer), length);
/*
* Reading 0 indicates end of file.
*/
if (total_bytes_read >= 0) {
result =
Dart_ArraySet(buffer_obj, offset, buffer, total_bytes_read);
ASSERT(Dart_IsValidResult(result));
return_value = total_bytes_read;
}
delete[] buffer;
}
Dart_SetReturnValue(args, Dart_NewInteger(return_value));
Dart_ExitScope();
}
void FUNCTION_NAME(File_WriteList)(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t return_value = -1;
File* file = GetFileHandle(Dart_GetNativeArgument(args, 0));
if (file != NULL) {
Dart_Handle buffer_obj = Dart_GetNativeArgument(args, 1);
assert(Dart_IsArray(buffer_obj));
int64_t offset =
DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 2));
int64_t length =
DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 3));
Dart_Result result = Dart_GetLength(buffer_obj);
assert(Dart_IsValidResult(result));
assert((offset + length) <= Dart_GetResultAsCIntptr(result));
uint8_t* buffer = new uint8_t[length];
result = Dart_ArrayGet(buffer_obj, offset, buffer, length);
ASSERT(Dart_IsValidResult(result));
int total_bytes_written =
file->Write(reinterpret_cast<void*>(buffer), length);
if (total_bytes_written >= 0) {
return_value = total_bytes_written;
}
delete[] buffer;
}
Dart_SetReturnValue(args, Dart_NewInteger(return_value));
Dart_ExitScope();
}
void FUNCTION_NAME(File_Position)(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t return_value = -1;
File* file = GetFileHandle(Dart_GetNativeArgument(args, 0));
if (file != NULL) {
return_value = file->Position();
}
Dart_SetReturnValue(args, Dart_NewInteger(return_value));
Dart_ExitScope();
}
void FUNCTION_NAME(File_Length)(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t return_value = -1;
File* file = GetFileHandle(Dart_GetNativeArgument(args, 0));
if (file != NULL) {
return_value = file->Length();
}
Dart_SetReturnValue(args, Dart_NewInteger(return_value));
Dart_ExitScope();
}
void FUNCTION_NAME(File_Flush)(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t return_value = -1;
File* file = GetFileHandle(Dart_GetNativeArgument(args, 0));
if (file != NULL) {
file->Flush();
return_value = 0;
}
Dart_SetReturnValue(args, Dart_NewInteger(return_value));
Dart_ExitScope();
}

65
runtime/bin/file.dart Normal file
View file

@ -0,0 +1,65 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
class FileIOException implements Exception {
const FileIOException([String message = ""]) : _message = message;
String getMessage() { return _message; }
final String _message;
}
interface FileInputStream extends InputStream factory _FileInputStream {
FileInputStream(File file);
}
interface FileOutputStream extends OutputStream factory _FileOutputStream {
FileOutputStream(File file);
}
interface File factory _File {
// Open a file.
File(String name, bool writable);
// Close the file.
void close();
// Synchronously read a single byte from the file.
// TODO(jrgfogh): Remove this call.
int readByte();
// Synchronously write a single byte to the file.
// TODO(jrgfogh): Remove this call.
int writeByte(int value);
// Synchronously write a single string to the file.
// TODO(jrgfogh): Remove this call.
int writeString(String string);
// Synchronously read a List<int> from the file.
// TODO(jrgfogh): Remove this call.
int readList(List<int> buffer, int offset, int bytes);
// Synchronously write a List<int> to the file.
// TODO(jrgfogh): Remove this call.
int writeList(List<int> buffer, int offset, int bytes);
// The current position of the file handle.
int get position();
// The length of the file.
int get length();
// Flush the contents of the file to disk.
void flush();
// Each file has an unique InputStream.
InputStream get inputStream();
// Each file has an unique OutputStream.
OutputStream get outputStream();
}
class FileUtil {
static bool fileExists(String name) native "File_Exists";
}

78
runtime/bin/file.h Normal file
View file

@ -0,0 +1,78 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef BIN_FILE_H_
#define BIN_FILE_H_
#if defined(_WIN32)
typedef signed __int64 int64_t;
typedef unsigned __int8 uint8_t;
#else
#include <stdint.h>
#endif
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
// Forward declaration.
class FileHandle;
class File {
public:
~File();
// Read/Write attempt to transfer num_bytes to/from buffer. It returns
// the number of bytes read/written.
int64_t Read(void* buffer, int64_t num_bytes);
int64_t Write(const void* buffer, int64_t num_bytes);
// ReadFully and WriteFully do attempt to transfer num_bytes to/from
// the buffer. In the event of short accesses they will loop internally until
// the whole buffer has been transferred or an error occurs. If an error
// occurred the result will be set to false.
bool ReadFully(void* buffer, int64_t num_bytes);
bool WriteFully(const void* buffer, int64_t num_bytes);
bool WriteByte(uint8_t byte) {
return WriteFully(&byte, 1);
}
// Get the length of the file. Returns a negative value if the length cannot
// be determined (e.g. not seekable device).
off_t Length();
// Get the current position in the file.
// Returns a negative value if position cannot be determined.
off_t Position();
// Flush contents of file.
void Flush();
const char* name() const { return name_; }
static File* OpenFile(const char* name, bool writable);
static bool FileExists(const char* name);
static bool IsAbsolutePath(const char* pathname);
static const char* PathSeparator();
static const char* StringEscapedPathSeparator();
private:
File(const char* name, FileHandle* handle) : name_(name), handle_(handle) { }
void Close();
bool IsClosed();
static const int kClosedFd = -1;
const char* name_;
// FileHandle is an OS specific class which stores data about the file.
FileHandle* handle_; // OS specific handle for the file.
// DISALLOW_COPY_AND_ASSIGN(File).
File(const File&);
void operator=(const File&);
};
#endif // BIN_FILE_H_

223
runtime/bin/file_impl.dart Normal file
View file

@ -0,0 +1,223 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
class _FileInputStream implements FileInputStream {
_FileInputStream(File file) {
_file = file;
}
bool read(List<int> buffer, int offset, int len, void callback()) {
int bytesRead = _file.readList(buffer, offset, len);
if (bytesRead == len) {
if (callback != null) {
callback();
}
return true;
} else {
throw "FileInputStream: read error";
}
}
// TODO(srdjan): Reading whole file at once does not scale. Implement partial
// file reading and pattern checks.
void readUntil(List<int> pattern, void callback(List<int> buffer)) {
List<int> buffer = new List<int>(_file.length);
int result = _file.readList(buffer, 0, _file.length);
if (result > 0) {
int index = indexOf(buffer, pattern);
if (index != -1) {
int resultBufferSize = index + pattern.length;
List<int> resultBuffer = new List<int>(resultBufferSize);
resultBuffer.copyFrom(buffer, 0, 0, resultBufferSize);
callback(resultBuffer);
}
}
}
// TODO(srdjan: move this method to Lists.dart (helper method).
static int indexOf(List<int> buffer, List<int> pattern) {
if (pattern.length == 0) {
return buffer.length;
}
int len = buffer.length - pattern.length + 1;
for (int index = 0; index < len; index++) {
bool match = true;
for (int k = 0; k < pattern.length; k++) {
if (buffer[index + k] != pattern[k]) {
match = false;
break;
}
}
if (match) {
return index;
}
}
return -1;
}
File _file;
}
class _FileOutputStream implements FileOutputStream {
_FileOutputStream(File file) {
_file = file;
}
bool write(List<int> buffer, int offset, int len, void callback()) {
int bytesWritten = _file.writeList(buffer, offset, len);
if (bytesWritten == len) {
return true;
} else {
throw "FileOutputStream: write error";
}
}
File _file;
}
// Class for encapsulating the native implementation of files.
class _File extends FileNativeWrapper implements File {
// Constructor for file.
factory _File(String name, bool writable) {
_File file = new _File._internal();
if (!file._openFile(name, writable)) {
return null;
}
file._writeable = writable;
return file;
}
_File._internal();
bool _openFile(String name, bool writable) native "File_OpenFile";
void close() {
_close();
}
int _close() native "File_Close";
int readByte() {
int result = _readByte();
if (result == -1) {
throw new FileIOException("Error: readByte failed");
}
return result;
}
int _readByte() native "File_ReadByte";
int writeByte(int value) {
int result = _writeByte(value);
if (result == -1) {
throw new FileIOException("Error: writeByte failed");
}
return result;
}
int _writeByte(int value) native "File_WriteByte";
int writeString(String string) {
int result = _writeString(string);
if (result == -1) {
throw new FileIOException("Error: writeString failed");
}
return result;
}
int _writeString(String string) native "File_WriteString";
int readList(List<int> buffer, int offset, int bytes) {
if (bytes == 0) {
return 0;
}
if (offset < 0) {
throw new IndexOutOfRangeException(offset);
}
if (bytes < 0) {
throw new IndexOutOfRangeException(bytes);
}
if ((offset + bytes) > buffer.length) {
throw new IndexOutOfRangeException(offset + bytes);
}
int result = _readList(buffer, offset, bytes);
if (result == -1) {
throw new FileIOException("Error: readList failed");
}
return result;
}
int _readList(List<int> buffer, int offset, int bytes)
native "File_ReadList";
int writeList(List<int> buffer, int offset, int bytes) {
if (bytes == 0) {
return 0;
}
if (offset < 0) {
throw new IndexOutOfRangeException(offset);
}
if (bytes < 0) {
throw new IndexOutOfRangeException(bytes);
}
if ((offset + bytes) > buffer.length) {
throw new IndexOutOfRangeException(offset + bytes);
}
int result = _writeList(buffer, offset, bytes);
if (result == -1) {
throw new FileIOException("Error: writeList failed");
}
return result;
}
int _writeList(List<int> buffer, int offset, int bytes)
native "File_WriteList";
int get position() {
int result = _position;
if (result == -1) {
throw new FileIOException("Error: get position failed");
}
return result;
}
int get _position() native "File_Position";
int get length() {
int result = _length;
if (result == -1) {
throw new FileIOException("Error: get length failed");
}
return result;
}
int get _length() native "File_Length";
void flush() {
int result = _flush();
if (result == -1) {
throw new FileIOException("Error: flush failed");
}
}
int _flush() native "File_Flush";
// Each file has an unique InputStream.
InputStream get inputStream() {
if (_inputStream === null) {
_inputStream = new FileInputStream(this);
}
return _inputStream;
}
// Each file has an unique OutputStream.
OutputStream get outputStream() {
if (!_writeable) {
throw "File is not writable";
}
if (_outputStream === null) {
_outputStream = new FileOutputStream(this);
}
return _outputStream;
}
// Set of native methods used to provide file functionality.
static bool fileExists(String name) native "File_Exists";
bool _writeable;
InputStream _inputStream;
OutputStream _outputStream;
}

128
runtime/bin/file_linux.cc Normal file
View file

@ -0,0 +1,128 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <libgen.h>
#include "bin/file.h"
class FileHandle {
public:
explicit FileHandle(int fd) : fd_(fd) { }
~FileHandle() { }
int fd() const { return fd_; }
void set_fd(int fd) { fd_ = fd; }
private:
int fd_;
// DISALLOW_COPY_AND_ASSIGN(FileHandle).
FileHandle(const FileHandle&);
void operator=(const FileHandle&);
};
File::~File() {
// Close the file (unless it's a standard stream).
if (handle_->fd() > STDERR_FILENO) {
Close();
}
delete handle_;
}
void File::Close() {
assert(handle_->fd() >= 0);
int err = close(handle_->fd());
if (err != 0) {
const int kBufferSize = 1024;
char error_message[kBufferSize];
strerror_r(errno, error_message, kBufferSize);
fprintf(stderr, "%s\n", error_message);
}
handle_->set_fd(kClosedFd);
}
bool File::IsClosed() {
return handle_->fd() == kClosedFd;
}
int64_t File::Read(void* buffer, int64_t num_bytes) {
assert(handle_->fd() >= 0);
return read(handle_->fd(), buffer, num_bytes);
}
int64_t File::Write(const void* buffer, int64_t num_bytes) {
assert(handle_->fd() >= 0);
return write(handle_->fd(), buffer, num_bytes);
}
off_t File::Position() {
assert(handle_->fd() >= 0);
return lseek(handle_->fd(), 0, SEEK_CUR);
}
void File::Flush() {
assert(handle_->fd() >= 0);
fsync(handle_->fd());
}
off_t File::Length() {
assert(handle_->fd() >= 0);
off_t position = lseek(handle_->fd(), 0, SEEK_CUR);
if (position < 0) {
// The file is not capable of seeking. Return an error.
return -1;
}
off_t result = lseek(handle_->fd(), 0, SEEK_END);
lseek(handle_->fd(), position, SEEK_SET);
return result;
}
File* File::OpenFile(const char* name, bool writable) {
int flags = O_RDONLY;
if (writable) {
flags = (O_RDWR | O_CREAT | O_TRUNC);
}
int fd = open(name, flags, 0666);
if (fd < 0) {
return NULL;
}
return new File(name, new FileHandle(fd));
}
bool File::FileExists(const char* name) {
struct stat st;
if (stat(name, &st) == 0) {
return S_ISREG(st.st_mode); // Deal with symlinks?
} else {
return false;
}
}
bool File::IsAbsolutePath(const char* pathname) {
return (pathname != NULL && pathname[0] == '/');
}
const char* File::PathSeparator() {
return "/";
}
const char* File::StringEscapedPathSeparator() {
return "/";
}

128
runtime/bin/file_macos.cc Normal file
View file

@ -0,0 +1,128 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <libgen.h>
#include "bin/file.h"
class FileHandle {
public:
explicit FileHandle(int fd) : fd_(fd) { }
~FileHandle() { }
int fd() const { return fd_; }
void set_fd(int fd) { fd_ = fd; }
private:
int fd_;
// DISALLOW_COPY_AND_ASSIGN(FileHandle).
FileHandle(const FileHandle&);
void operator=(const FileHandle&);
};
File::~File() {
// Close the file (unless it's a standard stream).
if (handle_->fd() > STDERR_FILENO) {
Close();
}
delete handle_;
}
void File::Close() {
assert(handle_->fd() >= 0);
int err = close(handle_->fd());
if (err != 0) {
const int kBufferSize = 1024;
char error_message[kBufferSize];
strerror_r(errno, error_message, kBufferSize);
fprintf(stderr, "%s\n", error_message);
}
handle_->set_fd(kClosedFd);
}
bool File::IsClosed() {
return handle_->fd() == kClosedFd;
}
int64_t File::Read(void* buffer, int64_t num_bytes) {
assert(handle_->fd() >= 0);
return read(handle_->fd(), buffer, num_bytes);
}
int64_t File::Write(const void* buffer, int64_t num_bytes) {
assert(handle_->fd() >= 0);
return write(handle_->fd(), buffer, num_bytes);
}
off_t File::Position() {
assert(handle_->fd() >= 0);
return lseek(handle_->fd(), 0, SEEK_CUR);
}
void File::Flush() {
assert(handle_->fd() >= 0);
fsync(handle_->fd());
}
off_t File::Length() {
assert(handle_->fd() >= 0);
off_t position = lseek(handle_->fd(), 0, SEEK_CUR);
if (position < 0) {
// The file is not capable of seeking. Return an error.
return -1;
}
off_t result = lseek(handle_->fd(), 0, SEEK_END);
lseek(handle_->fd(), position, SEEK_SET);
return result;
}
File* File::OpenFile(const char* name, bool writable) {
int flags = O_RDONLY;
if (writable) {
flags = (O_RDWR | O_CREAT | O_TRUNC);
}
int fd = open(name, flags, 0666);
if (fd < 0) {
return NULL;
}
return new File(name, new FileHandle(fd));
}
bool File::FileExists(const char* name) {
struct stat st;
if (stat(name, &st) == 0) {
return S_ISREG(st.st_mode); // Deal with symlinks?
} else {
return false;
}
}
bool File::IsAbsolutePath(const char* pathname) {
return (pathname != NULL && pathname[0] == '/');
}
const char* File::PathSeparator() {
return "/";
}
const char* File::StringEscapedPathSeparator() {
return "/";
}

60
runtime/bin/file_test.cc Normal file
View file

@ -0,0 +1,60 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "bin/file.h"
#include "vm/assert.h"
#include "vm/globals.h"
#include "vm/unit_test.h"
// Helper method to be able to run the test from the runtime
// directory, or the top directory.
static const char* GetFileName(const char* name) {
if (File::FileExists(name)) {
return name;
} else {
static const int kRuntimeLength = strlen("runtime/");
return name + kRuntimeLength;
}
}
UNIT_TEST_CASE(Read) {
const char* kFilename = GetFileName("runtime/bin/file_test.cc");
File* file = File::OpenFile(kFilename, false);
EXPECT(file != NULL);
EXPECT_STREQ(kFilename, file->name());
char buffer[16];
buffer[0] = '\0';
EXPECT(file->ReadFully(buffer, 13)); // ReadFully returns true.
buffer[13] = '\0';
EXPECT_STREQ("// Copyright ", buffer);
EXPECT(!file->WriteByte(1)); // Cannot write to a read-only file.
delete file;
}
UNIT_TEST_CASE(FileLength) {
const char* kFilename =
GetFileName("runtime/tests/vm/data/fixed_length_file");
File* file = File::OpenFile(kFilename, false);
EXPECT(file != NULL);
EXPECT_EQ(42, file->Length());
delete file;
}
UNIT_TEST_CASE(FilePosition) {
char buf[42];
const char* kFilename =
GetFileName("runtime/tests/vm/data/fixed_length_file");
File* file = File::OpenFile(kFilename, false);
EXPECT(file != NULL);
EXPECT(file->ReadFully(buf, 12));
EXPECT_EQ(12, file->Position());
EXPECT(file->ReadFully(buf, 6));
EXPECT_EQ(18, file->Position());
delete file;
}

130
runtime/bin/file_win.cc Normal file
View file

@ -0,0 +1,130 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include <fcntl.h>
#include <io.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include "bin/builtin.h"
#include "bin/file.h"
class FileHandle {
public:
explicit FileHandle(int fd) : fd_(fd) { }
~FileHandle() { }
int fd() const { return fd_; }
void set_fd(int fd) { fd_ = fd; }
private:
int fd_;
// DISALLOW_COPY_AND_ASSIGN(FileHandle).
FileHandle(const FileHandle&);
void operator=(const FileHandle&);
};
File::~File() {
// Close the file (unless it's a standard stream).
if (handle_->fd() > 2) {
Close();
}
delete handle_;
}
void File::Close() {
assert(handle_->fd() >= 0);
int err = close(handle_->fd());
if (err != 0) {
fprintf(stderr, "%s\n", strerror(errno));
}
handle_->set_fd(kClosedFd);
}
bool File::IsClosed() {
return handle_->fd() == kClosedFd;
}
int64_t File::Read(void* buffer, int64_t num_bytes) {
assert(handle_->fd() >= 0);
return read(handle_->fd(), buffer, num_bytes);
}
int64_t File::Write(const void* buffer, int64_t num_bytes) {
assert(handle_->fd() >= 0);
return write(handle_->fd(), buffer, num_bytes);
}
off_t File::Position() {
assert(handle_->fd() >= 0);
return lseek(handle_->fd(), 0, SEEK_CUR);
}
void File::Flush() {
assert(handle_->fd());
_commit(handle_->fd());
}
off_t File::Length() {
assert(handle_->fd() >= 0);
off_t position = lseek(handle_->fd(), 0, SEEK_CUR);
if (position < 0) {
// The file is not capable of seeking. Return an error.
return -1;
}
off_t result = lseek(handle_->fd(), 0, SEEK_END);
lseek(handle_->fd(), position, SEEK_SET);
return result;
}
File* File::OpenFile(const char* name, bool writable) {
int flags = O_RDONLY | O_BINARY;
if (writable) {
flags = (O_RDWR | O_CREAT | O_TRUNC | O_BINARY);
}
int fd = open(name, flags, 0666);
if (fd < 0) {
return NULL;
}
return new File(name, new FileHandle(fd));
}
bool File::FileExists(const char* name) {
struct stat st;
if (stat(name, &st) == 0) {
return ((st.st_mode & S_IFMT) == S_IFREG);
} else {
return false;
}
}
bool File::IsAbsolutePath(const char* pathname) {
// Should we consider network paths?
if (pathname == NULL) return false;
return (strlen(pathname) > 2) &&
(pathname[1] == ':') &&
(pathname[2] == '\\');
}
const char* File::PathSeparator() {
return "\\";
}
const char* File::StringEscapedPathSeparator() {
return "\\\\";
}

186
runtime/bin/gen_snapshot.cc Normal file
View file

@ -0,0 +1,186 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Generate a snapshot file after loading all the scripts specified on the
// command line.
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "include/dart_api.h"
#include "bin/builtin.h"
#include "bin/file.h"
#include "bin/globals.h"
#include "bin/process_script.h"
// Global state that indicates whether a snapshot is to be created and
// if so which file to write the snapshot into.
static const char* snapshot_filename = NULL;
static bool IsValidFlag(const char* name,
const char* prefix,
intptr_t prefix_length) {
intptr_t name_length = strlen(name);
return ((name_length > prefix_length) &&
(strncmp(name, prefix, prefix_length) == 0));
}
static const char* ProcessOption(const char* option, const char* name) {
const intptr_t length = strlen(name);
if (strncmp(option, name, length) == 0) {
return (option + length);
}
return NULL;
}
static bool ProcessSnapshotOption(const char* option) {
const char* kSnapshotOption = "--snapshot=";
snapshot_filename = ProcessOption(option, kSnapshotOption);
return snapshot_filename != NULL;
}
// Parse out the command line arguments. Returns -1 if the arguments
// are incorrect, 0 otherwise.
static int ParseArguments(int argc,
char** argv,
CommandLineOptions* vm_options,
char** script_name) {
const char* kPrefix = "--";
const intptr_t kPrefixLen = strlen(kPrefix);
// Skip the binary name.
int i = 1;
// Parse out the vm options.
while ((i < argc) && IsValidFlag(argv[i], kPrefix, kPrefixLen)) {
if (ProcessSnapshotOption(argv[i])) {
i += 1;
continue;
}
vm_options->AddArgument(argv[i]);
i += 1;
}
// Get the script name.
if (i < argc) {
*script_name = argv[i];
i += 1;
} else {
*script_name = NULL;
}
return 0;
}
static void WriteSnapshotFile(const uint8_t* buffer, const intptr_t size) {
const bool kWritable = true;
File* file = File::OpenFile(snapshot_filename, kWritable);
ASSERT(file != NULL);
for (intptr_t i = 0; i < size; i++) {
file->WriteByte(buffer[i]);
}
delete file;
}
static void* SnapshotCreateCallback(void* data) {
const char* script_name = reinterpret_cast<const char*>(data);
Dart_Result result;
Dart_EnterScope();
ASSERT(snapshot_filename != NULL);
// If a file is specified on the command line, load it up before a snapshot
// is created.
if (script_name != NULL) {
// Load the specified script.
result = LoadScript(script_name);
if (!Dart_IsValidResult(result)) {
const char* err_msg = Dart_GetErrorCString(result);
fprintf(stderr, "Errors encountered while loading script: %s\n", err_msg);
Dart_ExitScope();
exit(255);
}
Dart_Handle library = Dart_GetResult(result);
if (!Dart_IsLibrary(library)) {
fprintf(stderr,
"Expected a library when loading script: %s",
script_name);
Dart_ExitScope();
exit(255);
}
Builtin_ImportLibrary(library);
} else {
Builtin_LoadLibrary();
}
// Setup the native resolver for built in library functions.
Builtin_SetNativeResolver();
uint8_t* buffer = NULL;
intptr_t size = 0;
// First create the snapshot.
result = Dart_CreateSnapshot(&buffer, &size);
if (!Dart_IsValidResult(result)) {
const char* err_msg = Dart_GetErrorCString(result);
fprintf(stderr, "Error while creating snapshot: %s\n", err_msg);
Dart_ExitScope();
exit(255);
}
// Now write the snapshot out to specified file and exit.
WriteSnapshotFile(buffer, size);
Dart_ExitScope();
return data;
}
static void PrintUsage() {
fprintf(stderr,
"dart [<vm-flags>] "
"[<dart-script-file>]\n");
}
int main(int argc, char** argv) {
CommandLineOptions vm_options(argc);
char* script_name;
// Parse command line arguments.
if (ParseArguments(argc,
argv,
&vm_options,
&script_name) < 0) {
PrintUsage();
return 255;
}
if (snapshot_filename == NULL) {
fprintf(stderr, "No snapshot output file specified\n");
return 255;
}
// Initialize the Dart VM.
Dart_Initialize(vm_options.count(),
vm_options.arguments(),
SnapshotCreateCallback);
// Create an isolate. As a side effect, SnapshotCreateCallback
// gets called, which loads the script (if one is specified), its libraries
// and writes out a snapshot.
Dart_Isolate isolate = Dart_CreateIsolate(NULL, script_name);
if (isolate == NULL) {
return 255;
}
// Shutdown the isolate.
Dart_ShutdownIsolate();
return 0;
}

126
runtime/bin/globals.h Normal file
View file

@ -0,0 +1,126 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef BIN_GLOBALS_H_
#define BIN_GLOBALS_H_
#if defined(_WIN32)
// Cut down on the amount of stuff that gets included via windows.h.
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#define NOKERNEL
#define NOUSER
#define NOSERVICE
#define NOSOUND
#define NOMCX
#include <windows.h>
#endif
// Processor architecture detection. For more info on what's defined, see:
// http://msdn.microsoft.com/en-us/library/b0084kay.aspx
// http://www.agner.org/optimize/calling_conventions.pdf
// or with gcc, run: "echo | gcc -E -dM -"
#if defined(_M_X64) || defined(__x86_64__)
#define HOST_ARCH_X64 1
#define ARCH_IS_64_BIT 1
#elif defined(_M_IX86) || defined(__i386__)
#define HOST_ARCH_IA32 1
#define ARCH_IS_32_BIT 1
#elif defined(__ARMEL__)
#define HOST_ARCH_ARM 1
#define ARCH_IS_32_BIT 1
#else
#error Architecture was not detected as supported by Dart.
#endif
#if !defined(TARGET_ARCH_ARM)
#if !defined(TARGET_ARCH_X64)
#if !defined(TARGET_ARCH_IA32)
// No target architecture specified pick the one matching the host architecture.
#if defined(HOST_ARCH_ARM)
#define TARGET_ARCH_ARM 1
#elif defined(HOST_ARCH_X64)
#define TARGET_ARCH_X64 1
#elif defined(HOST_ARCH_IA32)
#define TARGET_ARCH_IA32 1
#else
#error Automatic target architecture detection failed.
#endif
#endif
#endif
#endif
// Verify that host and target architectures match, we cannot
// have a 64 bit Dart VM generating 32 bit code or vice-versa.
#if defined(TARGET_ARCH_X64)
#if !defined(ARCH_IS_64_BIT)
#error Mismatched Host/Target architectures.
#endif
#elif defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM)
#if !defined(ARCH_IS_32_BIT)
#error Mismatched Host/Target architectures.
#endif
#endif
// Target OS detection.
// for more information on predefined macros:
// - http://msdn.microsoft.com/en-us/library/b0084kay.aspx
// - with gcc, run: "echo | gcc -E -dM -"
#if defined(__linux__) || defined(__FreeBSD__)
#define TARGET_OS_LINUX 1
#elif defined(__APPLE__)
#define TARGET_OS_MACOS 1
#elif defined(_WIN32)
#define TARGET_OS_WINDOWS 1
#else
#error Automatic target os detection failed.
#endif
// A macro to disallow the copy constructor and operator= functions.
// This should be used in the private: declarations for a class.
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
private: \
TypeName(const TypeName&); \
void operator=(const TypeName&)
// A macro to disallow all the implicit constructors, namely the default
// constructor, copy constructor and operator= functions. This should be
// used in the private: declarations for a class that wants to prevent
// anyone from instantiating it. This is especially useful for classes
// containing only static methods.
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
private: \
TypeName(); \
DISALLOW_COPY_AND_ASSIGN(TypeName)
// Macro to disallow allocation in the C++ heap. This should be used
// in the private section for a class.
#define DISALLOW_ALLOCATION() \
public: \
void operator delete(void* pointer) { UNREACHABLE(); } \
private: \
void* operator new(size_t size);
// The USE(x) template is used to silence C++ compiler warnings issued
// for unused variables.
template <typename T>
static inline void USE(T) { }
// On Windows the reentrent version of strtok is called
// strtok_s. Unify on the posix name strtok_r.
#if defined(TARGET_OS_WINDOWS)
#define snprintf _snprintf
#define strtok_r strtok_s
#endif
#endif // BIN_GLOBALS_H_

View file

@ -0,0 +1,25 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/**
* Input is read from a given input stream. Such an input stream can
* be an endpoint, e.g., a socket or a file, or another input stream.
* Multiple input streams can be chained together to operate collaboratively
* on a given input.
*/
interface InputStream {
/**
* Reads [len] bytes into [buffer] buffer starting at [offset] offset.
* [callback] callback is invoked on completion unless it is null.
*/
bool read(List<int> buffer, int offset, int len, void callback());
/**
* Reads data from the stream into a buffer until a given [pattern] occurs and
* hands that buffer over as an input to the registered [callback].
* The callback is not invoked if a read error occurs.
*/
void readUntil(List<int> pattern, void callback(List<int> buffer));
}

257
runtime/bin/main.cc Normal file
View file

@ -0,0 +1,257 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "include/dart_api.h"
#include "bin/builtin.h"
#include "bin/file.h"
#include "bin/globals.h"
#include "bin/process_script.h"
// snapshot_buffer points to a snapshot if we link in a snapshot otherwise
// it is initialized to NULL.
extern const uint8_t* snapshot_buffer;
// Global state that indicates whether pprof symbol information is
// to be generated or not.
static const char* generate_pprof_symbols_filename = NULL;
static bool IsValidFlag(const char* name,
const char* prefix,
intptr_t prefix_length) {
intptr_t name_length = strlen(name);
return ((name_length > prefix_length) &&
(strncmp(name, prefix, prefix_length) == 0));
}
static const char* ProcessOption(const char* option, const char* name) {
const intptr_t length = strlen(name);
if (strncmp(option, name, length) == 0) {
return (option + length);
}
return NULL;
}
static bool ProcessPprofOption(const char* option) {
const char* kProfOption = "--generate_pprof_symbols=";
generate_pprof_symbols_filename = ProcessOption(option, kProfOption);
return generate_pprof_symbols_filename != NULL;
}
// Parse out the command line arguments. Returns -1 if the arguments
// are incorrect, 0 otherwise.
static int ParseArguments(int argc,
char** argv,
CommandLineOptions* vm_options,
char** script_name,
CommandLineOptions* dart_options) {
const char* kPrefix = "--";
const intptr_t kPrefixLen = strlen(kPrefix);
// Skip the binary name.
int i = 1;
// Parse out the vm options.
while ((i < argc) && IsValidFlag(argv[i], kPrefix, kPrefixLen)) {
if (ProcessPprofOption(argv[i])) {
i += 1;
Dart_InitPprofSupport();
continue;
}
vm_options->AddArgument(argv[i]);
i += 1;
}
// Get the script name.
if (i < argc) {
*script_name = argv[i];
i += 1;
} else {
return -1;
}
// Parse out options to be passed to dart main.
while (i < argc) {
dart_options->AddArgument(argv[i]);
i += 1;
}
return 0;
}
static void DumpPprofSymbolInfo() {
if (generate_pprof_symbols_filename != NULL) {
Dart_EnterScope();
File* pprof_file = File::OpenFile(generate_pprof_symbols_filename, true);
ASSERT(pprof_file != NULL);
void* buffer;
int buffer_size;
Dart_GetPprofSymbolInfo(&buffer, &buffer_size);
if (buffer_size > 0) {
ASSERT(buffer != NULL);
pprof_file->WriteFully(buffer, buffer_size);
}
delete pprof_file; // Closes the file.
Dart_ExitScope();
}
}
static void* MainIsolateInitCallback(void* data) {
const char* script_name = reinterpret_cast<const char*>(data);
Dart_Result result;
Dart_EnterScope();
// Load the specified script.
result = LoadScript(script_name);
if (!Dart_IsValidResult(result)) {
const char* err_msg = Dart_GetErrorCString(result);
fprintf(stderr, "Errors encountered while loading script: %s\n", err_msg);
Dart_ExitScope();
exit(255);
}
Dart_Handle library = Dart_GetResult(result);
if (!Dart_IsLibrary(library)) {
fprintf(stderr,
"Expected a library when loading script: %s",
script_name);
Dart_ExitScope();
exit(255);
}
Builtin_ImportLibrary(library);
// Setup the native resolver for built in library functions.
Builtin_SetNativeResolver();
Dart_ExitScope();
return data;
}
static void PrintUsage() {
fprintf(stderr,
"dart [<vm-flags>] <dart-script-file> [<dart-options>]\n");
}
static bool HasCompileAll(const CommandLineOptions& options) {
for (int i = 0; i < options.count(); i++) {
if (strcmp(options.GetArgument(i), "--compile_all") == 0) {
return true;
}
}
return false;
}
static void PrintObject(FILE* out, Dart_Handle object) {
Dart_Result result = Dart_ObjectToString(object);
if (Dart_IsValidResult(result)) {
Dart_Handle string = Dart_GetResult(result);
PrintString(out, string);
} else {
fprintf(out, "%s\n", Dart_GetErrorCString(result));
}
}
int main(int argc, char** argv) {
char* script_name;
CommandLineOptions vm_options(argc);
CommandLineOptions dart_options(argc);
// Parse command line arguments.
if (ParseArguments(argc,
argv,
&vm_options,
&script_name,
&dart_options) < 0) {
PrintUsage();
return 255;
}
// Initialize the Dart VM.
Dart_Initialize(vm_options.count(),
vm_options.arguments(),
MainIsolateInitCallback);
// Create an isolate. As a side effect, MainIsolateInitCallback
// gets called, which loads the scripts and libraries.
Dart_Isolate isolate = Dart_CreateIsolate(snapshot_buffer, script_name);
if (isolate == NULL) {
return 255;
}
Dart_EnterScope();
// TODO(asiva): Create a dart options object that can be accessed from
// dart code.
if (HasCompileAll(vm_options)) {
Dart_Result result = Dart_CompileAll();
if (!Dart_IsValidResult(result)) {
fprintf(stderr, "%s\n", Dart_GetErrorCString(result));
Dart_ExitScope();
Dart_ShutdownIsolate();
return 255; // Indicates we encountered an error.
}
}
// Lookup and invoke the top level main function.
Dart_Handle script_url = Dart_NewString(script_name);
Dart_Result result = Dart_LookupLibrary(script_url);
if (!Dart_IsValidResult(result)) {
fprintf(stderr, "%s\n", Dart_GetErrorCString(result));
Dart_ExitScope();
Dart_ShutdownIsolate();
return 255; // Indicates we encountered an error.
}
Dart_Handle library = Dart_GetResult(result);
result = Dart_InvokeStatic(library,
Dart_NewString(""),
Dart_NewString("main"),
0,
NULL);
if (Dart_IsValidResult(result)) {
Dart_Handle result_obj = Dart_GetResult(result);
if (Dart_ExceptionOccurred(result_obj)) {
// Print the exception object.
fprintf(stderr, "An unhandled exception has been thrown\n");
Dart_Result exception_result = Dart_GetException(result_obj);
assert(Dart_IsValidResult(exception_result));
PrintObject(stderr, Dart_GetResult(exception_result));
// Print the stack trace.
Dart_Result stacktrace = Dart_GetStacktrace(result_obj);
assert(Dart_IsValidResult(stacktrace));
PrintObject(stderr, Dart_GetResult(stacktrace));
fprintf(stderr, "\n");
Dart_ExitScope();
Dart_ShutdownIsolate();
return 255; // We had an unhandled exception, hence indicate an error.
}
} else {
fprintf(stderr, "%s\n", Dart_GetErrorCString(result));
Dart_ExitScope();
Dart_ShutdownIsolate();
return 255; // Indicates we encountered an error.
}
Dart_ExitScope();
// Keep handling messages until the last active receive port is closed.
Dart_RunLoop();
// Dump symbol information for the profiler.
DumpPprofSymbolInfo();
// Shutdown the isolate.
Dart_ShutdownIsolate();
return 0;
}

View file

@ -0,0 +1,19 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/**
* Output is written to a given output stream. Such an output stream can
* be an endpoint, e.g., a socket or a file, or another output stream.
* Multiple output streams can be chained together to operate collaboratively
* on a given output.
*/
interface OutputStream {
/**
* Writes [len] bytes into [buffer] buffer starting at [offset] offset].
* If write succeedes true is returned. Otherwise false is returned
* and [callback] callback is invoked on completion.
*/
bool write(List<int> buffer, int offset, int len, void callback());
}

70
runtime/bin/process.cc Normal file
View file

@ -0,0 +1,70 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "bin/dartutils.h"
#include "bin/process.h"
#include "include/dart_api.h"
void FUNCTION_NAME(Process_Start)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle process = Dart_GetNativeArgument(args, 0);
intptr_t in;
intptr_t out;
intptr_t err;
intptr_t exit_event;
const char* path =
DartUtils::GetStringValue(Dart_GetNativeArgument(args, 1));
Dart_Handle arguments = Dart_GetNativeArgument(args, 2);
ASSERT(Dart_IsArray(arguments));
Dart_Result result = Dart_GetLength(arguments);
ASSERT(Dart_IsValidResult(result));
intptr_t length = Dart_GetResultAsCIntptr(result);
char** string_args = new char*[length];
for (int i = 0; i < length; i++) {
result = Dart_ArrayGetAt(arguments, i);
ASSERT(Dart_IsValidResult(result));
Dart_Handle arg = Dart_GetResult(result);
string_args[i] = const_cast<char *>(DartUtils::GetStringValue(arg));
}
Dart_Handle in_handle = Dart_GetNativeArgument(args, 3);
Dart_Handle out_handle = Dart_GetNativeArgument(args, 4);
Dart_Handle err_handle = Dart_GetNativeArgument(args, 5);
Dart_Handle exit_handle = Dart_GetNativeArgument(args, 6);
Dart_Handle status_handle = Dart_GetNativeArgument(args, 7);
intptr_t pid = -1;
static const int kMaxChildOsErrorMessageLength = 256;
char os_error_message[kMaxChildOsErrorMessageLength];
int error_code = Process::Start(
path, string_args, length,
&in, &out, &err, &pid, &exit_event,
os_error_message, kMaxChildOsErrorMessageLength);
if (error_code == 0) {
DartUtils::SetIntegerInstanceField(in_handle, DartUtils::kIdFieldName, in);
DartUtils::SetIntegerInstanceField(
out_handle, DartUtils::kIdFieldName, out);
DartUtils::SetIntegerInstanceField(
err_handle, DartUtils::kIdFieldName, err);
DartUtils::SetIntegerInstanceField(
exit_handle, DartUtils::kIdFieldName, exit_event);
DartUtils::SetIntegerInstanceField(process, "_pid", pid);
} else {
DartUtils::SetIntegerInstanceField(
status_handle, "_errorCode", error_code);
DartUtils::SetStringInstanceField(
status_handle, "_errorMessage", os_error_message);
}
delete[] string_args;
Dart_SetReturnValue(args, Dart_NewBoolean(error_code == 0));
Dart_ExitScope();
}
void FUNCTION_NAME(Process_Kill)(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t pid = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 1));
bool success = Process::Kill(pid);
Dart_SetReturnValue(args, Dart_NewBoolean(success));
Dart_ExitScope();
}

66
runtime/bin/process.dart Normal file
View file

@ -0,0 +1,66 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
interface Process factory _Process {
/*
* Creates a new process object preparing to run the executable
* found at [path] with the specified [arguments]. [arguments] has
* to be a const string array, c.f. bug 5314640.
*/
Process(String path, List<String> arguments);
/*
* Start the process by running the specified executable. An
* exception of type [ProcessException] is thrown if the process
* cannot be started. There is a remote possibility of an exception
* being thrown even though the child process did actually start.
*/
void start();
/*
* Returns an input stream of the process stdout.
*/
InputStream get stdoutStream();
/*
* Returns an input stream of the process stderr.
*/
InputStream get stderrStream();
/*
* Returns an output stream to the process stdin.
*/
OutputStream get stdinStream();
/*
* Sets an exit handler which gets invoked when the process terminates.
*/
void setExitHandler(void callback(int exitCode));
/*
* Kills the process with [signal].
*/
bool kill();
/*
* Terminates the streams and closes the exit handler of a process.
*/
void close();
}
class ProcessException implements Exception {
const ProcessException([String this.message, int this.errorCode = 0]);
String toString() => "ProcessException: $message";
/*
* Contains the system message for the process exception if any.
*/
final String message;
/*
* Contains the OS error code for the process exception if any.
*/
final int errorCode;
}

31
runtime/bin/process.h Normal file
View file

@ -0,0 +1,31 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef BIN_PROCESS_H_
#define BIN_PROCESS_H_
#include "bin/builtin.h"
#include "bin/globals.h"
class Process {
public:
static int Start(const char* path,
char* arguments[],
intptr_t arguments_length,
intptr_t* in,
intptr_t* out,
intptr_t* err,
intptr_t* id,
intptr_t* exit_handler,
char* os_error_message,
int os_error_message_len);
static bool Kill(intptr_t id);
DISALLOW_ALLOCATION();
DISALLOW_IMPLICIT_CONSTRUCTORS(Process);
};
#endif // BIN_PROCESS_H_

View file

@ -0,0 +1,153 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
class _ProcessStartStatus {
int _errorCode; // Set to OS error code if process start failed.
String _errorMessage; // Set to OS error message if process start failed.
}
class _Process implements Process {
_Process(String path, List<String> arguments) {
_path = path;
{
int len = arguments.length;
_arguments = new ObjectArray<String>(len);
for (int i = 0; i < len; i++) {
_arguments[i] = arguments[i];
}
}
_in = new _Socket._internal();
_out = new _Socket._internal();
_err = new _Socket._internal();
_exitHandler = new _Socket._internal();
_closed = false;
_killed = false;
_started = false;
_exitHandlerCallback = null;
}
void start() {
var status = new _ProcessStartStatus();
bool success = _start(
_path, _arguments, _in, _out, _err, _exitHandler, status);
if (!success) {
close();
throw new ProcessException(status._errorMessage, status._errorCode);
}
_started = true;
if (_exitHandlerCallback !== null) {
setExitHandler(_exitHandlerCallback);
}
}
bool _start(String path,
List<String> arguments,
Socket input,
Socket output,
Socket error,
Socket exitHandler,
_ProcessStartStatus status) native "Process_Start";
InputStream get stdoutStream() {
if (_closed) {
throw new ProcessException("Process closed");
}
return _in.inputStream;
}
InputStream get stderrStream() {
if (_closed) {
throw new ProcessException("Process closed");
}
return _err.inputStream;
}
OutputStream get stdinStream() {
if (_closed) {
throw new ProcessException("Process closed");
}
return _out.outputStream;
}
bool kill() {
if (_closed && _pid == null) {
throw new ProcessException("Process closed");
}
if (_killed) {
return true;
}
if (_kill(_pid)) {
_killed = true;
return true;
}
return false;
}
void _kill(int pid) native "Process_Kill";
void close() {
if (_closed) {
throw new ProcessException("Process closed");
}
_in.close();
_out.close();
_err.close();
_exitHandler.close();
_closed = true;
}
void setExitHandler(void callback(int exitCode)) {
if (_closed) {
throw new ProcessException("Process closed");
}
if (_killed) {
throw new ProcessException("Process killed");
}
if (_started) {
_exitHandler.setDataHandler(() {
List<int> buffer = new List<int>(4);
SocketInputStream input = _exitHandler.inputStream;
int getExitValue(List<int> ints) {
return ints[0] + (ints[1] << 8) + (ints[2] << 16) + (ints[3] << 24);
}
void readData() {
callback(getExitValue(buffer));
}
bool result = input.read(buffer, 0, 4, readData);
if (result) {
callback(getExitValue(buffer));
}
});
} else {
_exitHandlerCallback = callback;
}
}
String _path;
ObjectArray<String> _arguments;
Socket _in;
Socket _out;
Socket _err;
Socket _exitHandler;
int _pid;
bool _closed;
bool _killed;
bool _started;
var _exitHandlerCallback;
}

View file

@ -0,0 +1,302 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "bin/fdutils.h"
#include "bin/process.h"
#include "bin/set.h"
class ActiveProcess {
public:
pid_t pid;
intptr_t fd;
bool operator==(const ActiveProcess &other) const {
if (pid == other.pid) {
return true;
}
return false;
}
};
static Set<ActiveProcess> activeProcesses;
static char* SafeStrNCpy(char* dest, const char* src, size_t n) {
strncpy(dest, src, n);
dest[n - 1] = '\0';
return dest;
}
static void SetChildOsErrorMessage(char* os_error_message,
int os_error_message_len) {
SafeStrNCpy(os_error_message, strerror(errno), os_error_message_len);
}
void ExitHandle(int processSignal, siginfo_t* siginfo, void* tmp) {
assert(processSignal == SIGCHLD);
struct sigaction act;
bzero(&act, sizeof(act));
act.sa_handler = SIG_IGN;
act.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
if (sigaction(SIGCHLD, &act, 0) != 0) {
perror("Process start: disabling signal handler failed");
}
pid_t pid = siginfo->si_pid;
ActiveProcess element;
element.pid = pid;
ActiveProcess* current = activeProcesses.Remove(element);
if (current != NULL) {
intptr_t message = siginfo->si_status;
intptr_t result =
FDUtils::WriteToBlocking(current->fd, &message, sizeof(message));
if (result != sizeof(message)) {
perror("ExitHandle notification failed");
}
close(current->fd);
delete current;
}
act.sa_handler = 0;
act.sa_sigaction = ExitHandle;
if (sigaction(SIGCHLD, &act, 0) != 0) {
perror("Process start: enabling signal handler failed");
}
}
int Process::Start(const char* path,
char* arguments[],
intptr_t arguments_length,
intptr_t* in,
intptr_t* out,
intptr_t* err,
intptr_t* id,
intptr_t* exit_event,
char* os_error_message,
int os_error_message_len) {
pid_t pid;
int read_in[2]; // Pipe for stdout to child process.
int read_err[2]; // Pipe for stderr to child process.
int write_out[2]; // Pipe for stdin to child process.
int exec_control[2]; // Pipe to get the result from exec.
int result;
result = pipe(read_in);
if (result < 0) {
SetChildOsErrorMessage(os_error_message, os_error_message_len);
fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
return errno;
}
result = pipe(read_err);
if (result < 0) {
SetChildOsErrorMessage(os_error_message, os_error_message_len);
close(read_in[0]);
close(read_in[1]);
fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
return errno;
}
result = pipe(write_out);
if (result < 0) {
SetChildOsErrorMessage(os_error_message, os_error_message_len);
close(read_in[0]);
close(read_in[1]);
close(read_err[0]);
close(read_err[1]);
fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
return errno;
}
result = pipe(exec_control);
if (result < 0) {
SetChildOsErrorMessage(os_error_message, os_error_message_len);
close(read_in[0]);
close(read_in[1]);
close(read_err[0]);
close(read_err[1]);
close(write_out[0]);
close(write_out[1]);
fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
return errno;
}
// Set close on exec on the write file descriptor of the exec control pipe.
result = fcntl(
exec_control[1], F_SETFD, fcntl(exec_control[1], F_GETFD) | FD_CLOEXEC);
if (result < 0) {
SetChildOsErrorMessage(os_error_message, os_error_message_len);
close(read_in[0]);
close(read_in[1]);
close(read_err[0]);
close(read_err[1]);
close(write_out[0]);
close(write_out[1]);
close(exec_control[0]);
close(exec_control[1]);
fprintf(stderr, "fcntl failed: %s\n", os_error_message);
return errno;
}
char* program_arguments[arguments_length + 2];
program_arguments[0] = const_cast<char *>(path);
for (int i = 0; i < arguments_length; i++) {
program_arguments[i + 1] = arguments[i];
}
program_arguments[arguments_length + 1] = NULL;
struct sigaction act;
bzero(&act, sizeof(act));
act.sa_sigaction = ExitHandle;
act.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
if (sigaction(SIGCHLD, &act, 0) != 0) {
perror("Process start: setting signal handler failed");
}
pid = fork();
if (pid < 0) {
SetChildOsErrorMessage(os_error_message, os_error_message_len);
close(read_in[0]);
close(read_in[1]);
close(read_err[0]);
close(read_err[1]);
close(write_out[0]);
close(write_out[1]);
close(exec_control[0]);
close(exec_control[1]);
return errno;
} else if (pid == 0) {
// Wait for parent process before setting up the child process.
char msg;
int bytes_read = FDUtils::ReadFromBlocking(read_in[0], &msg, sizeof(msg));
if (bytes_read != sizeof(msg)) {
perror("Failed receiving notification message");
exit(1);
}
close(write_out[1]);
close(read_in[0]);
close(read_err[0]);
close(exec_control[0]);
dup2(write_out[0], STDIN_FILENO);
close(write_out[0]);
dup2(read_in[1], STDOUT_FILENO);
close(read_in[1]);
dup2(read_err[1], STDERR_FILENO);
close(read_err[1]);
execvp(path, const_cast<char* const*>(program_arguments));
// In the case of failure write the errno and the OS error message
// to the exec control pipe.
int child_errno = errno;
char* os_error_message = strerror(errno);
ASSERT(sizeof(child_errno) == sizeof(errno));
int bytes_written =
FDUtils::WriteToBlocking(
exec_control[1], &child_errno, sizeof(child_errno));
if (bytes_written == sizeof(child_errno)) {
FDUtils::WriteToBlocking(
exec_control[1], os_error_message, strlen(os_error_message) + 1);
}
close(exec_control[1]);
exit(1);
}
int event_fds[2];
result = pipe(event_fds);
if (result < 0) {
SetChildOsErrorMessage(os_error_message, os_error_message_len);
close(read_in[0]);
close(read_in[1]);
close(read_err[0]);
close(read_err[1]);
close(write_out[0]);
close(write_out[1]);
fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
return errno;
}
ActiveProcess* activeProcess = new ActiveProcess();
activeProcess->pid = pid;
activeProcess->fd = event_fds[1];
activeProcesses.Add(*activeProcess);
*exit_event = event_fds[0];
FDUtils::SetNonBlocking(event_fds[0]);
// Notify child process to start.
char msg = '1';
result = FDUtils::WriteToBlocking(read_in[1], &msg, sizeof(msg));
if (result != sizeof(msg)) {
perror("Failed sending notification message");
}
// Read exec result from child. If no data is returned the exec was
// successful and the exec call closed the pipe. Otherwise the errno
// is written to the pipe.
close(exec_control[1]);
int child_errno;
int bytes_read = -1;
ASSERT(sizeof(child_errno) == sizeof(errno));
bytes_read =
FDUtils::ReadFromBlocking(
exec_control[0], &child_errno, sizeof(child_errno));
if (bytes_read == sizeof(child_errno)) {
bytes_read = FDUtils::ReadFromBlocking(exec_control[0],
os_error_message,
os_error_message_len);
os_error_message[os_error_message_len - 1] = '\0';
}
close(exec_control[0]);
// Return error code if any failures.
if (bytes_read != 0) {
close(read_in[0]);
close(read_in[1]);
close(read_err[0]);
close(read_err[1]);
close(write_out[0]);
close(write_out[1]);
if (bytes_read == -1) {
return errno; // Read failed.
} else {
return child_errno; // Exec failed.
}
}
FDUtils::SetNonBlocking(read_in[0]);
*in = read_in[0];
close(read_in[1]);
FDUtils::SetNonBlocking(write_out[1]);
*out = write_out[1];
close(write_out[0]);
FDUtils::SetNonBlocking(read_err[0]);
*err = read_err[0];
close(read_err[1]);
*id = pid;
return 0;
}
bool Process::Kill(intptr_t id) {
int result = kill(id, SIGKILL);
if (result == -1) {
return false;
}
return true;
}

View file

@ -0,0 +1,302 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "bin/fdutils.h"
#include "bin/process.h"
#include "bin/set.h"
class ActiveProcess {
public:
pid_t pid;
intptr_t fd;
bool operator==(const ActiveProcess &other) const {
if (pid == other.pid) {
return true;
}
return false;
}
};
static Set<ActiveProcess> activeProcesses;
static char* SafeStrNCpy(char* dest, const char* src, size_t n) {
strncpy(dest, src, n);
dest[n - 1] = '\0';
return dest;
}
static void SetChildOsErrorMessage(char* os_error_message,
int os_error_message_len) {
SafeStrNCpy(os_error_message, strerror(errno), os_error_message_len);
}
void ExitHandle(int processSignal, siginfo_t* siginfo, void* tmp) {
assert(processSignal == SIGCHLD);
struct sigaction act;
bzero(&act, sizeof(act));
act.sa_handler = SIG_IGN;
act.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
if (sigaction(SIGCHLD, &act, 0) != 0) {
perror("Process start: disabling signal handler failed");
}
pid_t pid = siginfo->si_pid;
ActiveProcess element;
element.pid = pid;
ActiveProcess* current = activeProcesses.Remove(element);
if (current != NULL) {
intptr_t message = siginfo->si_status;
intptr_t result =
FDUtils::WriteToBlocking(current->fd, &message, sizeof(message));
if (result != sizeof(message)) {
perror("ExitHandle notification failed");
}
close(current->fd);
delete current;
}
act.sa_handler = 0;
act.sa_sigaction = ExitHandle;
if (sigaction(SIGCHLD, &act, 0) != 0) {
perror("Process start: enabling signal handler failed");
}
}
int Process::Start(const char* path,
char* arguments[],
intptr_t arguments_length,
intptr_t* in,
intptr_t* out,
intptr_t* err,
intptr_t* id,
intptr_t* exit_event,
char* os_error_message,
int os_error_message_len) {
pid_t pid;
int read_in[2]; // Pipe for stdout to child process.
int read_err[2]; // Pipe for stderr to child process.
int write_out[2]; // Pipe for stdin to child process.
int exec_control[2]; // Pipe to get the result from exec.
int result;
result = pipe(read_in);
if (result < 0) {
SetChildOsErrorMessage(os_error_message, os_error_message_len);
fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
return errno;
}
result = pipe(read_err);
if (result < 0) {
SetChildOsErrorMessage(os_error_message, os_error_message_len);
close(read_in[0]);
close(read_in[1]);
fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
return errno;
}
result = pipe(write_out);
if (result < 0) {
SetChildOsErrorMessage(os_error_message, os_error_message_len);
close(read_in[0]);
close(read_in[1]);
close(read_err[0]);
close(read_err[1]);
fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
return errno;
}
result = pipe(exec_control);
if (result < 0) {
SetChildOsErrorMessage(os_error_message, os_error_message_len);
close(read_in[0]);
close(read_in[1]);
close(read_err[0]);
close(read_err[1]);
close(write_out[0]);
close(write_out[1]);
fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
return errno;
}
// Set close on exec on the write file descriptor of the exec control pipe.
result = fcntl(
exec_control[1], F_SETFD, fcntl(exec_control[1], F_GETFD) | FD_CLOEXEC);
if (result < 0) {
SetChildOsErrorMessage(os_error_message, os_error_message_len);
close(read_in[0]);
close(read_in[1]);
close(read_err[0]);
close(read_err[1]);
close(write_out[0]);
close(write_out[1]);
close(exec_control[0]);
close(exec_control[1]);
fprintf(stderr, "fcntl failed: %s\n", os_error_message);
return errno;
}
char* program_arguments[arguments_length + 2];
program_arguments[0] = const_cast<char *>(path);
for (int i = 0; i < arguments_length; i++) {
program_arguments[i + 1] = arguments[i];
}
program_arguments[arguments_length + 1] = NULL;
struct sigaction act;
bzero(&act, sizeof(act));
act.sa_sigaction = ExitHandle;
act.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
if (sigaction(SIGCHLD, &act, 0) != 0) {
perror("Process start: setting signal handler failed");
}
pid = fork();
if (pid < 0) {
SetChildOsErrorMessage(os_error_message, os_error_message_len);
close(read_in[0]);
close(read_in[1]);
close(read_err[0]);
close(read_err[1]);
close(write_out[0]);
close(write_out[1]);
close(exec_control[0]);
close(exec_control[1]);
return errno;
} else if (pid == 0) {
// Wait for parent process before setting up the child process.
char msg;
int bytes_read = FDUtils::ReadFromBlocking(read_in[0], &msg, sizeof(msg));
if (bytes_read != sizeof(msg)) {
perror("Failed receiving notification message");
exit(1);
}
close(write_out[1]);
close(read_in[0]);
close(read_err[0]);
close(exec_control[0]);
dup2(write_out[0], STDIN_FILENO);
close(write_out[0]);
dup2(read_in[1], STDOUT_FILENO);
close(read_in[1]);
dup2(read_err[1], STDERR_FILENO);
close(read_err[1]);
execvp(path, const_cast<char* const*>(program_arguments));
// In the case of failure write the errno and the OS error message
// to the exec control pipe.
int child_errno = errno;
char* os_error_message = strerror(errno);
ASSERT(sizeof(child_errno) == sizeof(errno));
int bytes_written =
FDUtils::WriteToBlocking(
exec_control[1], &child_errno, sizeof(child_errno));
if (bytes_written == sizeof(child_errno)) {
FDUtils::WriteToBlocking(
exec_control[1], os_error_message, strlen(os_error_message) + 1);
}
close(exec_control[1]);
exit(1);
}
int event_fds[2];
result = pipe(event_fds);
if (result < 0) {
SetChildOsErrorMessage(os_error_message, os_error_message_len);
close(read_in[0]);
close(read_in[1]);
close(read_err[0]);
close(read_err[1]);
close(write_out[0]);
close(write_out[1]);
fprintf(stderr, "Error pipe creation failed: %s\n", os_error_message);
return errno;
}
ActiveProcess* activeProcess = new ActiveProcess();
activeProcess->pid = pid;
activeProcess->fd = event_fds[1];
activeProcesses.Add(*activeProcess);
*exit_event = event_fds[0];
FDUtils::SetNonBlocking(event_fds[0]);
// Notify child process to start.
char msg = '1';
result = FDUtils::WriteToBlocking(read_in[1], &msg, sizeof(msg));
if (result != sizeof(msg)) {
perror("Failed sending notification message");
}
// Read exec result from child. If no data is returned the exec was
// successful and the exec call closed the pipe. Otherwise the errno
// is written to the pipe.
close(exec_control[1]);
int child_errno;
int bytes_read = -1;
ASSERT(sizeof(child_errno) == sizeof(errno));
bytes_read =
FDUtils::ReadFromBlocking(
exec_control[0], &child_errno, sizeof(child_errno));
if (bytes_read == sizeof(child_errno)) {
bytes_read = FDUtils::ReadFromBlocking(exec_control[0],
os_error_message,
os_error_message_len);
os_error_message[os_error_message_len - 1] = '\0';
}
close(exec_control[0]);
// Return error code if any failures.
if (bytes_read != 0) {
close(read_in[0]);
close(read_in[1]);
close(read_err[0]);
close(read_err[1]);
close(write_out[0]);
close(write_out[1]);
if (bytes_read == -1) {
return errno; // Read failed.
} else {
return child_errno; // Exec failed.
}
}
FDUtils::SetNonBlocking(read_in[0]);
*in = read_in[0];
close(read_in[1]);
FDUtils::SetNonBlocking(write_out[1]);
*out = write_out[1];
close(write_out[0]);
FDUtils::SetNonBlocking(read_err[0]);
*err = read_err[0];
close(read_err[1]);
*id = pid;
return 0;
}
bool Process::Kill(intptr_t id) {
int result = kill(id, SIGKILL);
if (result == -1) {
return false;
}
return true;
}

View file

@ -0,0 +1,158 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Handle dart scripts.
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "include/dart_api.h"
#include "bin/builtin.h"
#include "bin/file.h"
#include "bin/globals.h"
#include "bin/process_script.h"
static const char* CanonicalizeUrl(const char* reference_dir,
const char* filename) {
static const char* kDartScheme = "dart:";
static const intptr_t kDartSchemeLen = strlen(kDartScheme);
// If the URL starts with "dart:" then it is not modified as it will be
// handled by the VM internally.
if (strncmp(filename, kDartScheme, kDartSchemeLen) == 0) {
return strdup(filename);
}
if (File::IsAbsolutePath(filename)) {
return strdup(filename);
}
char* path = strdup(reference_dir);
if (path == NULL) {
return NULL;
}
char* path_sep = strrchr(path, File::PathSeparator()[0]);
if (path_sep == NULL) {
// No separator found: Reference is a file in local directory.
return strdup(filename);
}
*path_sep = '\0';
intptr_t len = snprintf(NULL, 0, "%s%s%s",
path, File::PathSeparator(), filename);
char* absolute_filename = reinterpret_cast<char*>(malloc(len + 1));
ASSERT(absolute_filename != NULL);
snprintf(absolute_filename, len + 1, "%s%s%s",
path, File::PathSeparator(), filename);
free(path);
return absolute_filename;
}
static Dart_Result ReadStringFromFile(const char* filename) {
File* file = File::OpenFile(filename, false);
if (file == NULL) {
const char* format = "Unable to open file: %s";
intptr_t len = snprintf(NULL, 0, format, filename);
// TODO(iposva): Allocate from the zone instead of leaking error string
// here. On the other hand the binary is about the exit anyway.
char* error_msg = reinterpret_cast<char*>(malloc(len + 1));
snprintf(error_msg, len + 1, format, filename);
return Dart_ErrorResult(error_msg);
}
intptr_t len = file->Length();
char* text_buffer = reinterpret_cast<char*>(malloc(len + 1));
if (text_buffer == NULL) {
delete file;
return Dart_ErrorResult("Unable to allocate buffer");
}
if (!file->ReadFully(text_buffer, len)) {
delete file;
return Dart_ErrorResult("Unable to fully read contents");
}
text_buffer[len] = '\0';
delete file;
Dart_Handle str = Dart_NewString(text_buffer);
free(text_buffer);
return Dart_ResultAsObject(str);
}
static Dart_Result LibraryTagHandler(Dart_LibraryTag tag,
Dart_Handle library,
Dart_Handle url) {
if (!Dart_IsLibrary(library)) {
return Dart_ErrorResult("not a library");
}
if (!Dart_IsString8(url)) {
return Dart_ErrorResult("url is not a string");
}
Dart_Result result = Dart_StringToCString(url);
if (!Dart_IsValidResult(result)) {
return Dart_ErrorResult("accessing url characters failed");
}
const char* url_chars = Dart_GetResultAsCString(result);
if (tag == kCanonicalizeUrl) {
// Create the full path based on the including library and the current url.
// Get the url of the calling library.
result = Dart_LibraryUrl(library);
if (!Dart_IsValidResult(result)) {
return Dart_ErrorResult("accessing library url failed");
}
Dart_Handle library_url = Dart_GetResult(result);
if (!Dart_IsString8(library_url)) {
return Dart_ErrorResult("library url is not a string");
}
result = Dart_StringToCString(library_url);
if (!Dart_IsValidResult(result)) {
return Dart_ErrorResult("accessing library url characters failed");
}
const char* library_url_chars = Dart_GetResultAsCString(result);
// Calculate the path.
const char* canon_url_chars = CanonicalizeUrl(library_url_chars, url_chars);
Dart_Handle canon_url = Dart_NewString(canon_url_chars);
free(const_cast<char*>(canon_url_chars));
return Dart_ResultAsObject(canon_url);
}
// The tag is either an import or a source tag. Read the file based on the
// url chars.
result = ReadStringFromFile(url_chars);
if (!Dart_IsValidResult(result)) {
return result;
}
Dart_Handle source = Dart_GetResult(result);
if (tag == kImportTag) {
result = Dart_LoadLibrary(url, source);
if (Dart_IsValidResult(result)) {
// TODO(iposva): Should the builtin library be added to all libraries?
Dart_Handle new_lib = Dart_GetResult(result);
Builtin_ImportLibrary(new_lib);
}
return result;
} else if (tag == kSourceTag) {
return Dart_LoadSource(library, url, source);
}
return Dart_ErrorResult("wrong tag");
}
Dart_Result LoadScript(const char* script_name) {
Dart_Result result = ReadStringFromFile(script_name);
if (!Dart_IsValidResult(result)) {
return result;
}
Dart_Handle source = Dart_GetResult(result);
Dart_Handle url = Dart_NewString(script_name);
return Dart_LoadScript(url, source, LibraryTagHandler);
}

View file

@ -0,0 +1,60 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef BIN_PROCESS_SCRIPT_H_
#define BIN_PROCESS_SCRIPT_H_
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
class CommandLineOptions {
public:
explicit CommandLineOptions(int max_count)
: count_(0), max_count_(max_count), arguments_(NULL) {
static const int kWordSize = sizeof(intptr_t);
arguments_ = reinterpret_cast<char **>(malloc(max_count * kWordSize));
if (arguments_ == NULL) {
max_count_ = 0;
}
}
~CommandLineOptions() {
free(arguments_);
count_ = 0;
max_count_ = 0;
arguments_ = NULL;
}
int count() const { return count_; }
char** arguments() const { return arguments_; }
char* GetArgument(int index) const {
return (index >= 0 && index < count_) ? arguments_[index] : NULL;
}
void AddArgument(char* argument) {
if (count_ < max_count_) {
arguments_[count_] = argument;
count_ += 1;
} else {
abort(); // We should never get into this situation.
}
}
void operator delete(void* pointer) { abort(); }
private:
void* operator new(size_t size);
CommandLineOptions(const CommandLineOptions&);
void operator=(const CommandLineOptions&);
int count_;
int max_count_;
char** arguments_;
};
extern Dart_Result LoadScript(const char* script_name);
#endif // BIN_PROCESS_SCRIPT_H_

View file

@ -0,0 +1,57 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* Run ./process_test <outstream> <echocount> <exitcode> <crash>
* <outstream>: 0 = stdout, 1 = stderr, 2 = stdout and stderr
* <echocount>: program terminates after <echocount> replies
* <exitcode>: program terminates with exit code <exitcode>
* <crash>: 0 = program terminates regularly, 1 = program segfaults
*/
int main(int argc, char* argv[]) {
if (argc != 5) {
fprintf(stderr,
"./process_test <outstream> <echocount> <exitcode> <crash>\n");
exit(1);
}
int outstream = atoi(argv[1]);
if (outstream < 0 || outstream > 2) {
fprintf(stderr, "unknown outstream");
exit(1);
}
int echo_counter = 0;
int echo_count = atoi(argv[2]);
int exit_code = atoi(argv[3]);
int crash = atoi(argv[4]);
const int kLineSize = 128;
char line[kLineSize];
while ((echo_count != echo_counter) &&
(fgets(line, kLineSize, stdin) != NULL)) {
if (outstream == 0) {
fprintf(stdout, "%s", line);
} else if (outstream == 1) {
fprintf(stderr, "%s", line);
} else if (outstream == 2) {
fprintf(stdout, "%s", line);
fprintf(stderr, "%s", line);
}
echo_counter++;
}
if (crash == 1) {
int* segfault = NULL;
*segfault = 1;
}
return exit_code;
}

View file

@ -0,0 +1,89 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "bin/builtin.h"
#include "bin/globals.h"
#include "bin/process.h"
int Process::Start(const char* path,
char* arguments[],
intptr_t arguments_length,
intptr_t* in,
intptr_t* out,
intptr_t* err,
intptr_t* id,
intptr_t* exit_event,
char* os_error_message,
int os_error_message_len) {
// Setup info structures.
STARTUPINFO startup_info;
PROCESS_INFORMATION process_info;
ZeroMemory(&startup_info, sizeof(startup_info));
startup_info.cb = sizeof(startup_info);
ZeroMemory(&process_info, sizeof(process_info));
// TODO(ager): Once sockets are implemented, use the supplied
// arguments as in, out and err in the startup info.
// Compute command-line length.
int command_line_length = strlen(path);
for (int i = 0; i < arguments_length; i++) {
command_line_length += strlen(arguments[i]);
}
// Account for two occurrences of '"' around the command, one
// space per argument and a terminating '\0'.
command_line_length += 2 + arguments_length + 1;
static const int kMaxCommandLineLength = 32768;
if (command_line_length > kMaxCommandLineLength) {
return 1;
}
// Put together command-line string.
char* command_line = new char[command_line_length];
int len = 0;
int remaining = command_line_length;
int written = snprintf(command_line + len, remaining, "\"%s\"", path);
len += written;
remaining -= written;
ASSERT(remaining >= 0);
for (int i = 0; i < arguments_length; i++) {
written = snprintf(command_line + len, remaining, " %s", arguments[i]);
len += written;
remaining -= written;
ASSERT(remaining >= 0);
}
// Create process.
BOOL result = CreateProcess(NULL, // ApplicationName
command_line,
NULL, // ProcessAttributes
NULL, // ThreadAttributes
FALSE, // InheritHandles
0, // CreationFlags
NULL, // Environment
NULL, // CurrentDirectory,
&startup_info,
&process_info);
// Deallocate command-line string.
delete[] command_line;
if (result == 0) {
return 1;
}
// Return process handle.
*id = reinterpret_cast<intptr_t>(process_info.hProcess);
return 0;
}
bool Process::Kill(intptr_t id) {
HANDLE process_handle = reinterpret_cast<HANDLE>(id);
BOOL result = TerminateProcess(process_handle, -1);
if (result == 0) {
return false;
}
CloseHandle(process_handle);
return true;
}

View file

@ -0,0 +1,98 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include <stdio.h>
#include "vm/dart.h"
#include "vm/unit_test.h"
// TODO(iposva, asiva): This is a placeholder for the real unittest framework.
namespace dart {
// Only run tests that match the filter string. The default does not match any
// tests.
static const char* const kNoTests = "No Test";
static const char* const kAllTests = "All Tests";
static const char* const kListTests = "List Tests";
static const char* test_filter = kNoTests;
static int test_matches = 0;
void TestCase::Run() {
fprintf(stdout, "Running test: %s\n", name());
(*run_)();
fprintf(stdout, "Done: %s\n", name());
}
void TestCaseBase::RunTest() {
if ((test_filter == kAllTests) || (strcmp(test_filter, this->name()) == 0)) {
this->Run();
test_matches++;
} else if (test_filter == kListTests) {
fprintf(stdout, "%s\n", this->name());
test_matches++;
}
}
static void PrintUsage() {
fprintf(stderr, "run_vm_tests [--list | --all | <test name>]\n");
fprintf(stderr, "run_vm_tests <test name> [vm-flags ...]\n");
}
static void* TestIsolateInitCallback(void* data) {
ASSERT(data == NULL);
return reinterpret_cast<void*>(0);
}
static int Main(int argc, char** argv) {
// Flags being passed to the Dart VM.
int dart_argc = 0;
char** dart_argv = NULL;
if (argc < 2) {
// Bad parameter count.
PrintUsage();
return 1;
} else if (argc == 2) {
if (strcmp(argv[1], "--list") == 0) {
test_filter = kListTests;
// List all the tests and exit without initializing the VM at all.
TestCaseBase::RunAll();
return 0;
} else if (strcmp(argv[1], "--all") == 0) {
test_filter = kAllTests;
} else {
test_filter = argv[1];
}
} else {
// First argument is the test name, the rest are vm flags.
test_filter = argv[1];
// Remove the first two values from the arguments.
dart_argc = argc - 2;
dart_argv = &argv[2];
}
bool init_success = Dart::InitOnce(dart_argc, dart_argv,
TestIsolateInitCallback);
ASSERT(init_success);
// Apply the test filter to all registered tests.
TestCaseBase::RunAll();
// Print a warning message if no tests were matched.
if (test_matches == 0) {
fprintf(stderr, "No tests matched: %s\n", test_filter);
return 1;
}
return 0;
}
} // namespace dart
int main(int argc, char** argv) {
return dart::Main(argc, argv);
}

128
runtime/bin/set.h Normal file
View file

@ -0,0 +1,128 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef BIN_SET_H_
#define BIN_SET_H_
#include <stdlib.h>
/*
* Set implements a collection of distinct objects.
*/
template <class T>
class Set {
private:
struct Node {
T object_;
Node* next_;
};
public:
class Iterator {
public:
explicit Iterator(Set<T>* list) : list_(list) {
if (list != NULL) {
next_ = list->head_;
} else {
next_ = NULL;
}
}
bool HasNext() const {
return next_ != NULL;
}
void GetNext(T* entry) {
*entry = next_->object_;
next_ = next_->next_;
}
private:
const Set<T>* list_;
struct Node* next_;
};
Set() {
head_ = NULL;
tail_ = NULL;
size_ = 0;
}
~Set() {}
bool Add(const T& element) {
Node* new_node = new Node;
new_node->object_ = element;
new_node->next_ = NULL;
if (Contains(element)) {
return false;
}
if (IsEmpty()) {
head_ = new_node;
tail_ = new_node;
} else {
tail_->next_ = new_node;
tail_ = new_node;
}
size_++;
return true;
}
T* Remove(const T& element) {
Node* current = head_;
Node* previous = NULL;
if (IsEmpty()) {
return NULL;
}
do {
if (element == current->object_) {
if (current == head_) {
head_ = head_->next_;
}
if (current == tail_) {
tail_ = previous;
}
if (previous != NULL) {
previous->next_ = current->next_;
}
size_--;
return &current->object_;
}
previous = current;
current = current->next_;
} while (current);
return NULL;
}
bool Contains(const T& element) {
T value;
Iterator iterator(this);
while (iterator.HasNext()) {
iterator.GetNext(&value);
if (value == element) {
return true;
}
}
return false;
}
bool IsEmpty() {
return head_ == NULL;
}
int Size() {
return size_;
}
private:
Node* head_;
Node* tail_;
int size_;
};
#endif // BIN_SET_H_

125
runtime/bin/set_test.cc Normal file
View file

@ -0,0 +1,125 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "bin/set.h"
#include "vm/unit_test.h"
UNIT_TEST_CASE(SetOperations) {
Set<int> set;
EXPECT(set.IsEmpty());
EXPECT(!set.Contains(1));
EXPECT(set.Add(1));
EXPECT(set.Contains(1));
EXPECT(!set.IsEmpty());
EXPECT(!set.Remove(2));
EXPECT(!set.IsEmpty());
EXPECT(set.Remove(1));
EXPECT(set.IsEmpty());
EXPECT(set.Add(3));
EXPECT(set.Contains(3));
EXPECT(!set.IsEmpty());
EXPECT(set.Add(4));
EXPECT(set.Contains(4));
EXPECT(!set.IsEmpty());
EXPECT(set.Add(5));
EXPECT(set.Contains(5));
EXPECT(set.Remove(5));
EXPECT(set.Remove(4));
EXPECT(set.Remove(3));
EXPECT(set.IsEmpty());
EXPECT(set.Add(1));
EXPECT(set.Contains(1));
EXPECT(set.Add(2));
EXPECT(set.Contains(2));
EXPECT(set.Add(3));
EXPECT(set.Contains(3));
EXPECT(!set.IsEmpty());
EXPECT(set.Size() == 3);
EXPECT(set.Remove(2));
EXPECT(set.Remove(1));
EXPECT(set.Remove(3));
EXPECT(set.IsEmpty());
EXPECT(set.Size() == 0);
EXPECT(set.Add(1));
EXPECT(set.Contains(1));
EXPECT(set.Add(2));
EXPECT(set.Contains(2));
EXPECT(set.Add(3));
EXPECT(set.Contains(3));
EXPECT(!set.IsEmpty());
EXPECT(set.Remove(2));
EXPECT(set.Remove(3));
EXPECT(set.Remove(1));
EXPECT(set.IsEmpty());
EXPECT(set.Add(1));
EXPECT(set.Contains(1));
EXPECT(set.Add(2));
EXPECT(set.Contains(2));
EXPECT(!set.IsEmpty());
EXPECT(set.Remove(2));
EXPECT(!set.IsEmpty());
EXPECT(set.Add(3));
EXPECT(set.Contains(3));
EXPECT(set.Add(4));
EXPECT(set.Contains(4));
EXPECT(!set.Contains(2));
EXPECT(!set.IsEmpty());
EXPECT(set.Remove(3));
EXPECT(!set.IsEmpty());
EXPECT(set.Remove(4));
EXPECT(set.Remove(1));
EXPECT(set.IsEmpty());
EXPECT(!set.Contains(4));
EXPECT(set.Add(1));
EXPECT(set.Contains(1));
EXPECT(!set.IsEmpty());
EXPECT(!set.Add(1));
EXPECT(set.Size() == 1);
EXPECT(set.Contains(1));
EXPECT(!set.IsEmpty());
EXPECT(set.Add(2));
EXPECT(set.Contains(2));
EXPECT(!set.IsEmpty());
EXPECT(!set.Add(2));
EXPECT(set.Contains(2));
EXPECT(!set.IsEmpty());
EXPECT(set.Size() == 2);
EXPECT(set.Remove(1));
EXPECT(set.Remove(2));
EXPECT(set.IsEmpty());
EXPECT(set.Size() == 0);
}
UNIT_TEST_CASE(SetIterator) {
Set<int> set;
int i;
for (i = 1; i <= 10; i++) {
set.Add(i);
}
Set<int>::Iterator iterator(&set);
int value;
i = 0;
while (iterator.HasNext()) {
iterator.GetNext(&value);
i++;
}
EXPECT(i == 10);
EXPECT(!set.IsEmpty());
Set<int> emptyset;
Set<int>::Iterator emptyiterator(&emptyset);
i = 0;
while (emptyiterator.HasNext()) {
emptyiterator.GetNext(&value);
i++;
}
EXPECT(i == 0);
EXPECT(emptyset.IsEmpty());
}

View file

@ -0,0 +1,16 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// This file is linked into the dart executable when it does not have a
// snapshot linked into it.
#if defined(_WIN32)
typedef unsigned __int8 uint8_t;
#else
#include <inttypes.h>
#include <stdint.h>
#endif
#include <stddef.h>
const uint8_t* snapshot_buffer = NULL;

View file

@ -0,0 +1,22 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// This file is linked into the dart executable when it has a snapshot
// linked into it.
#if defined(_WIN32)
typedef unsigned __int8 uint8_t;
#else
#include <inttypes.h>
#include <stdint.h>
#endif
#include <stddef.h>
// The string on the next line will be filled in with the contents of the
// generated snapshot binary file.
// This string forms the content of a snapshot which is loaded in by dart.
static const uint8_t snapshot_buffer_[] = {
%s
};
const uint8_t* snapshot_buffer = snapshot_buffer_;

143
runtime/bin/socket.cc Normal file
View file

@ -0,0 +1,143 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "bin/socket.h"
#include "bin/dartutils.h"
#include "include/dart_api.h"
void FUNCTION_NAME(Socket_CreateConnect)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle socketobj = Dart_GetNativeArgument(args, 0);
const char* host =
DartUtils::GetStringValue(Dart_GetNativeArgument(args, 1));
intptr_t port = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 2));
intptr_t socket = Socket::CreateConnect(host, port);
DartUtils::SetIntegerInstanceField(
socketobj, DartUtils::kIdFieldName, socket);
Dart_SetReturnValue(args, Dart_NewBoolean(socket >= 0));
Dart_ExitScope();
}
void FUNCTION_NAME(Socket_Available)(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t socket =
DartUtils::GetIntegerInstanceField(Dart_GetNativeArgument(args, 0),
DartUtils::kIdFieldName);
intptr_t available = Socket::Available(socket);
Dart_SetReturnValue(args, Dart_NewInteger(available));
Dart_ExitScope();
}
void FUNCTION_NAME(Socket_ReadList)(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t socket =
DartUtils::GetIntegerInstanceField(Dart_GetNativeArgument(args, 0),
DartUtils::kIdFieldName);
Dart_Handle buffer_obj = Dart_GetNativeArgument(args, 1);
assert(Dart_IsArray(buffer_obj));
intptr_t offset =
DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 2));
intptr_t length =
DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 3));
Dart_Result result = Dart_GetLength(buffer_obj);
assert(Dart_IsValidResult(result));
assert((offset + length) <= Dart_GetResultAsCIntptr(result));
if (Dart_IsVMFlagSet("short_socket_read")) {
length = (length + 1) / 2;
}
uint8_t* buffer = new uint8_t[length];
intptr_t bytes_read = Socket::Read(socket, buffer, length);
if (bytes_read > 0) {
Dart_Result result = Dart_ArraySet(buffer_obj, offset, buffer, bytes_read);
ASSERT(Dart_IsValidResult(result));
} else if (bytes_read < 0) {
bytes_read = 0;
}
delete[] buffer;
Dart_SetReturnValue(args, Dart_NewInteger(bytes_read));
Dart_ExitScope();
}
void FUNCTION_NAME(Socket_WriteList)(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t socket =
DartUtils::GetIntegerInstanceField(Dart_GetNativeArgument(args, 0),
DartUtils::kIdFieldName);
Dart_Handle buffer_obj = Dart_GetNativeArgument(args, 1);
assert(Dart_IsArray(buffer_obj));
intptr_t offset =
DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 2));
intptr_t length =
DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 3));
Dart_Result result = Dart_GetLength(buffer_obj);
assert(Dart_IsValidResult(result));
assert((offset + length) <= Dart_GetResultAsCIntptr(result));
if (Dart_IsVMFlagSet("short_socket_write")) {
length = (length + 1) / 2;
}
uint8_t* buffer = new uint8_t[length];
result = Dart_ArrayGet(buffer_obj, offset, buffer, length);
ASSERT(Dart_IsValidResult(result));
intptr_t total_bytes_written =
Socket::Write(socket, reinterpret_cast<void*>(buffer), length);
delete[] buffer;
if (total_bytes_written < 0) {
total_bytes_written = 0;
}
Dart_SetReturnValue(args, Dart_NewInteger(total_bytes_written));
Dart_ExitScope();
}
void FUNCTION_NAME(Socket_GetPort)(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t socket =
DartUtils::GetIntegerInstanceField(Dart_GetNativeArgument(args, 0),
DartUtils::kIdFieldName);
intptr_t port = Socket::GetPort(socket);
Dart_SetReturnValue(args, Dart_NewInteger(port));
Dart_ExitScope();
}
void FUNCTION_NAME(ServerSocket_CreateBindListen)(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle socketobj = Dart_GetNativeArgument(args, 0);
const char* bindAddress =
DartUtils::GetStringValue(Dart_GetNativeArgument(args, 1));
intptr_t port = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 2));
intptr_t backlog =
DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 3));
intptr_t socket =
ServerSocket::CreateBindListen(bindAddress, port, backlog);
DartUtils::SetIntegerInstanceField(
socketobj, DartUtils::kIdFieldName, socket);
Dart_SetReturnValue(args, Dart_NewBoolean(socket >= 0));
Dart_ExitScope();
}
void FUNCTION_NAME(ServerSocket_Accept)(Dart_NativeArguments args) {
Dart_EnterScope();
intptr_t socket =
DartUtils::GetIntegerInstanceField(Dart_GetNativeArgument(args, 0),
DartUtils::kIdFieldName);
Dart_Handle socketobj = Dart_GetNativeArgument(args, 1);
intptr_t newSocket = ServerSocket::Accept(socket);
if (newSocket >= 0) {
DartUtils::SetIntegerInstanceField(
socketobj, DartUtils::kIdFieldName, newSocket);
}
Dart_SetReturnValue(args, Dart_NewBoolean(newSocket >= 0));
Dart_ExitScope();
}

116
runtime/bin/socket.dart Normal file
View file

@ -0,0 +1,116 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
interface ServerSocket factory _ServerSocket {
/*
* Constructs a new server socket, binds it to a given address and port,
* and listens on it.
*/
ServerSocket(String bindAddress, int port, int backlog);
/*
* Accepts a connection to this socket.
*/
Socket accept();
/*
* The connection handler gets executed when there are incoming connections
* on the socket.
*/
void setConnectionHandler(void callback());
/*
* The error handler gets executed when a socket error occurs.
*/
void setErrorHandler(void callback());
/*
* Returns the port used by this socket.
*/
int get port();
/*
* Closes the socket.
*/
void close();
}
interface Socket factory _Socket {
/*
* Constructs a new socket and connects it to the given host on the given
* port.
*/
Socket(String host, int port);
/*
* Returns the number of received and non-read bytes in the socket that
* can be read.
*/
int available();
/*
* Reads up to [count] bytes of data from the socket and stores them into
* buffer after buffer offset [offset]. The number of successfully read
* bytes is returned. This function is non-blocking and will only read data
* if data is available.
*/
int readList(List<int> buffer, int offset, int count);
/*
* Writes up to [count] bytes of the buffer from [offset] buffer offset to
* the socket. The number of successfully written bytes is returned. This
* function is non-blocking and will only write data if buffer space is
* available in the socket. It will return 0 if an error occurs, e.g., no
* buffer space available.
*/
int writeList(List<int> buffer, int offset, int count);
/*
* The connect handler gets executed when connection to a given host
* succeeded.
*/
void setConnectHandler(void callback());
/*
* The data handler gets executed when data becomes available at the socket.
*/
void setDataHandler(void callback());
/*
* The write handler gets executed when the socket becomes available for
* writing.
*/
void setWriteHandler(void callback());
/*
* The error handler gets executed when a socket error occurs.
*/
void setErrorHandler(void callback());
/*
* The close handler gets executed when the socket was closed.
*/
void setCloseHandler(void callback());
/*
* Returns input stream to the socket.
*/
InputStream get inputStream();
/*
* Returns output stream of the socket.
*/
OutputStream get outputStream();
/*
* Returns the port used by this socket.
*/
int get port();
/*
* Closes the socket
*/
void close();
}

37
runtime/bin/socket.h Normal file
View file

@ -0,0 +1,37 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef BIN_SOCKET_H_
#define BIN_SOCKET_H_
#include "bin/builtin.h"
#include "bin/globals.h"
class Socket {
public:
static bool Initialize();
static intptr_t Available(intptr_t fd);
static intptr_t Read(intptr_t fd, void* buffer, intptr_t num_bytes);
static intptr_t Write(intptr_t fd, const void* buffer, intptr_t num_bytes);
static intptr_t CreateConnect(const char* host, const intptr_t port);
static intptr_t GetPort(intptr_t fd);
DISALLOW_ALLOCATION();
DISALLOW_IMPLICIT_CONSTRUCTORS(Socket);
};
class ServerSocket {
public:
static intptr_t Accept(intptr_t fd);
static intptr_t CreateBindListen(const char* bindAddress,
intptr_t port,
intptr_t backlog);
DISALLOW_ALLOCATION();
DISALLOW_IMPLICIT_CONSTRUCTORS(ServerSocket);
};
#endif // BIN_SOCKET_H_

View file

@ -0,0 +1,287 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
class SocketIOException {
const SocketIOException([String message = ""]) : message_ = message;
String getMessage() { return message_; }
final String message_;
}
/*
* SocketNativeWrapper is defined in native and holds a field to store the
* native socket object.
*/
class SocketBase {
/*
* Keep these constants in sync with the native poll event identifiers.
*/
static final int _IN_EVENT = 0;
static final int _OUT_EVENT = 1;
static final int _ERROR_EVENT = 2;
static final int _CLOSE_EVENT = 3;
static final int _CLOSE_COMMAND = 4;
SocketBase () {
_handler = new ReceivePort();
_handlerMap = new List(_CLOSE_EVENT + 1);
_handlerMask = 0;
_canActivateHandlers = true;
_id = 0;
_handler.receive((var message, ignored) {
_multiplex(message);
});
EventHandler._start();
}
/*
* Multiplexes socket events to the right socket handler.
*/
void _multiplex(List<int> message) {
assert(message.length == 1);
_canActivateHandlers = false;
int event_mask = message[0];
for (int i = _IN_EVENT; i <= _CLOSE_EVENT; i++) {
if (((event_mask & (1 << i)) != 0) && _handlerMap[i] !== null) {
var handleEvent = _handlerMap[i];
/*
* Unregister the out handler before executing it.
*/
if (i == _OUT_EVENT) {
_setHandler(i, null);
}
handleEvent();
}
}
_canActivateHandlers = true;
_doActivateHandlers();
}
void _setHandler(int event, void callback()) {
if (callback === null) {
_handlerMask &= ~(1 << event);
} else {
_handlerMask |= (1 << event);
}
_handlerMap[event] = callback;
_doActivateHandlers();
}
void _getPort() native "Socket_GetPort";
void setErrorHandler(void callback()) {
_setHandler(_ERROR_EVENT, callback);
}
void _doActivateHandlers() {
if (_canActivateHandlers && (_id >= 0)) {
EventHandler._sendData(_id, _handler, _handlerMask);
}
}
int get port() {
if (_port == null) {
_port = _getPort();
}
return _port;
}
void close() {
if (_id >= 0) {
EventHandler._sendData(_id, _handler, 1 << _CLOSE_COMMAND);
_handler.close();
_id = -1;
} else {
throw new
SocketIOException("Error: close failed - invalid socket handle");
}
}
/*
* Socket id is set from native. -1 indicates that the socket was closed.
*/
int _id;
/*
* Dedicated ReceivePort for socket events.
*/
ReceivePort _handler;
/*
* Poll event to handler map.
*/
List _handlerMap;
/*
* Indicates for which poll events the socket registered handlers.
*/
int _handlerMask;
/*
* Indicates if native interrupts can be activated.
*/
bool _canActivateHandlers;
/*
* Holds the port of the socket, null if not known.
*/
int _port;
}
class _ServerSocket extends SocketBase implements ServerSocket {
/*
* Constructor for server socket. First a socket object is allocated
* in which the native socket is stored. After that _createBind
* is called which creates a file descriptor and binds the given address
* and port to the socket. Null is returned if file descriptor creation or
* bind failed.
*/
factory _ServerSocket(String bindAddress, int port, int backlog) {
ServerSocket socket = new _ServerSocket._internal();
if (!socket._createBindListen(bindAddress, port, backlog)) {
return null;
}
if (port != 0) {
socket._port = port;
}
return socket;
}
_ServerSocket._internal() : super() {}
Socket accept() {
if (_id >= 0) {
_Socket socket = new _Socket._internal();
if (_accept(socket)) {
return socket;
}
return null;
}
throw new
SocketIOException("Error: accept failed - invalid socket handle");
}
bool _accept(Socket socket) native "ServerSocket_Accept";
bool _createBindListen(String bindAddress, int port, int backlog)
native "ServerSocket_CreateBindListen";
void setConnectionHandler(void callback()) {
_setHandler(_IN_EVENT, callback);
}
}
class _Socket extends SocketBase implements Socket {
/*
* Constructor for socket. First a socket object is allocated
* in which the native socket is stored. After that _createConnect is
* called which creates a file discriptor and connects to the given
* host on the given port. Null is returned if file descriptor creation
* or connect failsed
*/
factory _Socket(String host, int port) {
Socket socket = new _Socket._internal();
if (!socket._createConnect(host, port)) {
return null;
}
return socket;
}
_Socket._internal() : super() {}
int available() {
if (_id >= 0) {
return _available();
}
throw new
SocketIOException("Error: available failed - invalid socket handle");
}
int _available() native "Socket_Available";
int readList(List<int> buffer, int offset, int bytes) {
if (_id >= 0) {
if (bytes == 0) {
return 0;
}
if (offset < 0) {
throw new IndexOutOfRangeException(offset);
}
if (bytes < 0) {
throw new IndexOutOfRangeException(bytes);
}
if ((offset + bytes) > buffer.length) {
throw new IndexOutOfRangeException(offset + bytes);
}
return _readList(buffer, offset, bytes);
}
throw new
SocketIOException("Error: readList failed - invalid socket handle");
}
int _readList(List<int> buffer, int offset, int bytes)
native "Socket_ReadList";
int writeList(List<int> buffer, int offset, int bytes) {
if (_id >= 0) {
if (bytes == 0) {
return 0;
}
if (offset < 0) {
throw new IndexOutOfRangeException(offset);
}
if (bytes < 0) {
throw new IndexOutOfRangeException(bytes);
}
if ((offset + bytes) > buffer.length) {
throw new IndexOutOfRangeException(offset + bytes);
}
return _writeList(buffer, offset, bytes);
}
throw new
SocketIOException("Error: writeList failed - invalid socket handle");
}
int _writeList(List<int> buffer, int offset, int bytes)
native "Socket_WriteList";
bool _createConnect(String host, int port) native "Socket_CreateConnect";
void setWriteHandler(void callback()) {
_setHandler(_OUT_EVENT, callback);
}
void setConnectHandler(void callback()) {
_setHandler(_OUT_EVENT, callback);
}
void setDataHandler(void callback()) {
_setHandler(_IN_EVENT, callback);
}
void setCloseHandler(void callback()) {
_setHandler(_CLOSE_EVENT, callback);
}
InputStream get inputStream() {
if (_inputStream === null) {
_inputStream = new SocketInputStream(this);
}
return _inputStream;
}
OutputStream get outputStream() {
if (_outputStream === null) {
_outputStream = new SocketOutputStream(this);
}
return _outputStream;
}
SocketInputStream _inputStream;
SocketOutputStream _outputStream;
}

138
runtime/bin/socket_linux.cc Normal file
View file

@ -0,0 +1,138 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include <arpa/inet.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include "bin/fdutils.h"
#include "bin/socket.h"
bool Socket::Initialize() {
// Nothing to do on Linux.
return true;
}
intptr_t Socket::CreateConnect(const char* host, const intptr_t port) {
intptr_t fd;
struct hostent* server;
struct sockaddr_in server_address;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) {
fprintf(stderr, "Error CreateConnect: %s\n", strerror(errno));
return -1;
}
FDUtils::SetNonBlocking(fd);
server = gethostbyname(host);
if (server == NULL) {
close(fd);
fprintf(stderr, "Error CreateConnect: %s\n", strerror(errno));
return -1;
}
server_address.sin_family = AF_INET;
server_address.sin_port = htons(port);
bcopy(server->h_addr, &server_address.sin_addr.s_addr, server->h_length);
memset(&server_address.sin_zero, 0, sizeof(server_address.sin_zero));
intptr_t result = connect(fd,
reinterpret_cast<struct sockaddr *>(&server_address),
sizeof(server_address));
if (result == 0 || errno == EINPROGRESS) {
return fd;
}
return -1;
}
intptr_t Socket::Available(intptr_t fd) {
return FDUtils::AvailableBytes(fd);
}
intptr_t Socket::Read(intptr_t fd,
void* buffer,
intptr_t num_bytes) {
assert(fd >= 0);
intptr_t read_bytes = read(fd, buffer, num_bytes);
return read_bytes;
}
intptr_t Socket::Write(intptr_t fd, const void* buffer, intptr_t num_bytes) {
assert(fd >= 0);
return write(fd, buffer, num_bytes);
}
intptr_t Socket::GetPort(intptr_t fd) {
assert(fd >= 0);
struct sockaddr_in socket_address;
socklen_t size = sizeof(socket_address);
if (getsockname(fd, reinterpret_cast<struct sockaddr *>(&socket_address),
&size)) {
fprintf(stderr, "Error getsockname: %s\n", strerror(errno));
return 0;
}
return ntohs(socket_address.sin_port);
}
intptr_t ServerSocket::CreateBindListen(const char* host,
intptr_t port,
intptr_t backlog) {
intptr_t fd;
struct sockaddr_in server_address;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) {
fprintf(stderr, "Error CreateBind: %s\n", strerror(errno));
return -1;
}
int optval = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
server_address.sin_family = AF_INET;
server_address.sin_port = htons(port);
server_address.sin_addr.s_addr = inet_addr(host);
memset(&server_address.sin_zero, 0, sizeof(server_address.sin_zero));
if (bind(fd, reinterpret_cast<struct sockaddr *>(&server_address),
sizeof(server_address)) < 0) {
close(fd);
fprintf(stderr, "Error Bind: %s\n", strerror(errno));
return -1;
}
if (listen(fd, backlog) != 0) {
fprintf(stderr, "Error Listen: %s\n", strerror(errno));
return -1;
}
FDUtils::SetNonBlocking(fd);
return fd;
}
intptr_t ServerSocket::Accept(intptr_t fd) {
intptr_t socket;
struct sockaddr clientaddr;
socklen_t addrlen = sizeof(clientaddr);
socket = accept(fd, &clientaddr, &addrlen);
if (socket < 0) {
fprintf(stderr, "Error Accept: %s\n", strerror(errno));
} else {
FDUtils::SetNonBlocking(socket);
}
return socket;
}

138
runtime/bin/socket_macos.cc Normal file
View file

@ -0,0 +1,138 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include <arpa/inet.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include "bin/fdutils.h"
#include "bin/socket.h"
bool Socket::Initialize() {
// Nothing to do on Mac OS.
return true;
}
intptr_t Socket::CreateConnect(const char* host, const intptr_t port) {
intptr_t fd;
struct hostent* server;
struct sockaddr_in server_address;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) {
fprintf(stderr, "Error CreateConnect: %s\n", strerror(errno));
return -1;
}
FDUtils::SetNonBlocking(fd);
server = gethostbyname(host);
if (server == NULL) {
close(fd);
fprintf(stderr, "Error CreateConnect: %s\n", strerror(errno));
return -1;
}
server_address.sin_family = AF_INET;
server_address.sin_port = htons(port);
bcopy(server->h_addr, &server_address.sin_addr.s_addr, server->h_length);
memset(&server_address.sin_zero, 0, sizeof(server_address.sin_zero));
intptr_t result = connect(fd,
reinterpret_cast<struct sockaddr *>(&server_address),
sizeof(server_address));
if (result == 0 || errno == EINPROGRESS) {
return fd;
}
return -1;
}
intptr_t Socket::Available(intptr_t fd) {
return FDUtils::AvailableBytes(fd);
}
intptr_t Socket::Read(intptr_t fd,
void* buffer,
intptr_t num_bytes) {
assert(fd >= 0);
intptr_t read_bytes = read(fd, buffer, num_bytes);
return read_bytes;
}
intptr_t Socket::Write(intptr_t fd, const void* buffer, intptr_t num_bytes) {
assert(fd >= 0);
return write(fd, buffer, num_bytes);
}
intptr_t Socket::GetPort(intptr_t fd) {
assert(fd >= 0);
struct sockaddr_in socket_address;
socklen_t size = sizeof(socket_address);
if (getsockname(fd, reinterpret_cast<struct sockaddr *>(&socket_address),
&size)) {
fprintf(stderr, "Error getsockname: %s\n", strerror(errno));
return 0;
}
return ntohs(socket_address.sin_port);
}
intptr_t ServerSocket::CreateBindListen(const char* host,
intptr_t port,
intptr_t backlog) {
intptr_t fd;
struct sockaddr_in server_address;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) {
fprintf(stderr, "Error CreateBind: %s\n", strerror(errno));
return -1;
}
int optval = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
server_address.sin_family = AF_INET;
server_address.sin_port = htons(port);
server_address.sin_addr.s_addr = inet_addr(host);
memset(&server_address.sin_zero, 0, sizeof(server_address.sin_zero));
if (bind(fd, reinterpret_cast<struct sockaddr *>(&server_address),
sizeof(server_address)) < 0) {
close(fd);
fprintf(stderr, "Error Bind: %s\n", strerror(errno));
return -1;
}
if (listen(fd, backlog) != 0) {
fprintf(stderr, "Error Listen: %s\n", strerror(errno));
return -1;
}
FDUtils::SetNonBlocking(fd);
return fd;
}
intptr_t ServerSocket::Accept(intptr_t fd) {
intptr_t socket;
struct sockaddr clientaddr;
socklen_t addrlen = sizeof(clientaddr);
socket = accept(fd, &clientaddr, &addrlen);
if (socket < 0) {
fprintf(stderr, "Error Accept: %s\n", strerror(errno));
} else {
FDUtils::SetNonBlocking(socket);
}
return socket;
}

View file

@ -0,0 +1,166 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
class SocketInputStream implements InputStream {
SocketInputStream(Socket socket) {
_socket = socket;
_buffer = null;
}
bool read(List<int> buffer, int offset, int len, void callback()) {
// Read data just out of the buffer.
if (_buffer !== null && len <= _buffer.length) {
buffer.copyFrom(_buffer, 0, offset, len);
int remainder = _buffer.length - len;
if (remainder > 0) {
List<int> newBuffer = new List<int>(remainder);
newBuffer.copyFrom(_buffer, 0, len, remainder);
_buffer = newBuffer;
} else {
_buffer = null;
}
return true;
}
// Read data out of the buffer if available and from the socket.
else {
int bytesRead = 0;
if (_buffer !== null) {
buffer.copyFrom(_buffer, offset, 0, _buffer.length);
bytesRead = _buffer.length;
_buffer = null;
}
bytesRead +=
_socket.readList(buffer, offset + bytesRead, len - bytesRead);
if (bytesRead == len) {
return true;
}
void doRead() {
bytesRead +=
_socket.readList(buffer, offset + bytesRead, len - bytesRead);
if (bytesRead < len) {
_socket.setDataHandler(doRead);
} else {
assert(bytesRead == len);
_socket.setDataHandler(null);
if (callback !== null) {
callback();
}
}
}
_socket.setDataHandler(doRead);
return false;
}
}
int _matchPattern(List<int> buffer, List<int> pattern, int start) {
int j;
if (pattern.length > buffer.length) {
return -1;
}
for (int i = start; i < (buffer.length - pattern.length + 1); i++) {
for (j = 0; j < pattern.length; j++) {
if (buffer[i + j] != pattern[j]) {
break;
}
}
if (j == pattern.length) {
return i;
}
}
return -1;
}
/*
* Appends the newBuffer to the buffer (if available), sets the buffer to
* null, and returns the merged buffer.
*/
List<int> _getBufferedData(List<int> newBuffer, int appendingBufferSpace) {
List<int> buffer;
int newDataStart = 0;
if (_buffer !== null) {
buffer = new List<int>(_buffer.length + appendingBufferSpace);
buffer.copyFrom(_buffer, 0, 0, _buffer.length);
newDataStart = _buffer.length;
_buffer = null;
} else {
buffer = new List<int>(appendingBufferSpace);
}
buffer.copyFrom(newBuffer, 0, newDataStart, appendingBufferSpace);
return buffer;
}
void readUntil(List<int> pattern, void callback(List<int> buffer)) {
void doRead() {
int size = _socket.available();
List<int> buffer = new List<int>(size);
int result = _socket.readList(buffer, 0, size);
if (result > 0) {
// TODO(hpayer): Avoid copying of data before pattern matching.
List<int> newBuffer = _getBufferedData(buffer, result);
int index = _matchPattern(newBuffer, pattern, 0);
// If pattern was found return the data including pattern and store the
// remainder in the buffer.
if (index != -1) {
int finalBufferSize = index + pattern.length;
List<int> finalBuffer = new List<int>(finalBufferSize);
finalBuffer.copyFrom(newBuffer, 0, 0, finalBufferSize);
if (finalBufferSize < newBuffer.length) {
List<int> remainder =
new List<int>(newBuffer.length - finalBufferSize);
remainder.copyFrom(buffer, finalBufferSize, 0, newBuffer.length);
_buffer = remainder;
}
_socket.setDataHandler(null);
callback(finalBuffer);
} else {
_buffer = newBuffer;
}
}
}
_socket.setDataHandler(doRead);
}
Socket _socket;
/*
* Read and readUntil read data out of that buffer first before reading new
* data out of the socket.
*/
List<int> _buffer;
}
class SocketOutputStream implements OutputStream {
SocketOutputStream(Socket socket) {
_socket = socket;
}
bool write(List<int> buffer, int offset, int len, void callback()) {
int bytesWritten = _socket.writeList(buffer, offset, len);
void finishWrite() {
bytesWritten += _socket.writeList(
buffer, offset + bytesWritten, len - bytesWritten);
if (bytesWritten < len) {
_socket.setWriteHandler(finishWrite);
} else {
assert(bytesWritten == len);
if (callback !== null) {
callback();
}
}
}
if (bytesWritten == len) {
return true;
}
_socket.setWriteHandler(finishWrite);
return false;
}
Socket _socket;
}

147
runtime/bin/socket_win.cc Normal file
View file

@ -0,0 +1,147 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include <winsock2.h>
#include <ws2tcpip.h>
#include <mswsock.h>
#include "bin/builtin.h"
#include "bin/eventhandler.h"
#include "bin/socket.h"
bool Socket::Initialize() {
int err;
WSADATA winsock_data;
WORD version_requested = MAKEWORD(1, 0);
err = WSAStartup(version_requested, &winsock_data);
if (err != 0) {
fprintf(stderr, "Unable to initialize Winsock: %d\n", WSAGetLastError());
}
return err == 0;
}
intptr_t Socket::Available(intptr_t fd) {
ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(fd);
return client_socket->Available();
}
intptr_t Socket::Read(intptr_t fd, void* buffer, intptr_t num_bytes) {
ASSERT(reinterpret_cast<Handle*>(fd)->is_client_socket());
ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(fd);
return client_socket->Read(buffer, num_bytes);
}
intptr_t Socket::Write(intptr_t fd, const void* buffer, intptr_t num_bytes) {
ASSERT(reinterpret_cast<Handle*>(fd)->is_client_socket());
ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(fd);
return client_socket->Write(buffer, num_bytes);
}
intptr_t Socket::GetPort(intptr_t fd) {
ASSERT(reinterpret_cast<Handle*>(fd)->is_socket());
SocketHandle* socket_handle = reinterpret_cast<SocketHandle*>(fd);
struct sockaddr_in socket_address;
socklen_t size = sizeof(socket_address);
if (getsockname(socket_handle->socket(),
reinterpret_cast<struct sockaddr *>(&socket_address),
&size)) {
fprintf(stderr, "Error getsockname: %s\n", strerror(errno));
return 0;
}
return ntohs(socket_address.sin_port);
}
intptr_t Socket::CreateConnect(const char* host, const intptr_t port) {
SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
if (s == INVALID_SOCKET) {
fprintf(stderr, "Error CreateConnect: %d\n", WSAGetLastError());
return -1;
}
struct hostent* server = gethostbyname(host);
if (server == NULL) {
fprintf(stderr, "Error CreateConnect: %d\n", WSAGetLastError());
closesocket(s);
return -1;
}
struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(port);
server_address.sin_addr.s_addr = inet_addr(host);
int status = connect(
s,
reinterpret_cast<struct sockaddr *>(&server_address),
sizeof(server_address));
if (status == SOCKET_ERROR) {
fprintf(stderr, "Error CreateConnect: %d\n", WSAGetLastError());
closesocket(s);
return -1;
}
ClientSocket* client_socket = new ClientSocket(s);
return reinterpret_cast<intptr_t>(client_socket);
}
intptr_t ServerSocket::Accept(intptr_t fd) {
ListenSocket* listen_socket = reinterpret_cast<ListenSocket*>(fd);
ClientSocket* client_socket = listen_socket->Accept();
if (client_socket != NULL) {
return reinterpret_cast<intptr_t>(client_socket);
} else {
return -1;
}
}
intptr_t ServerSocket::CreateBindListen(const char* host,
intptr_t port,
intptr_t backlog) {
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET) {
fprintf(stderr, "Error CreateBindListen: %d\n", WSAGetLastError());
return -1;
}
BOOL optval = true;
int status = setsockopt(s,
SOL_SOCKET,
SO_REUSEADDR,
reinterpret_cast<const char*>(&optval),
sizeof(optval));
if (status == SOCKET_ERROR) {
fprintf(stderr, "Error CreateBindListen: %d\n", WSAGetLastError());
closesocket(s);
return -1;
}
sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(host);
addr.sin_port = htons(port);
status = bind(s,
reinterpret_cast<struct sockaddr *>(&addr),
sizeof(addr));
if (status == SOCKET_ERROR) {
fprintf(stderr, "Error CreateBindListen: %d\n", WSAGetLastError());
closesocket(s);
return -1;
}
status = listen(s, backlog);
if (status == SOCKET_ERROR) {
fprintf(stderr, "Error socket listen: %d\n", WSAGetLastError());
closesocket(s);
return -1;
}
ListenSocket* listen_socket = new ListenSocket(s);
return reinterpret_cast<intptr_t>(listen_socket);
}

19
runtime/bin/timer.dart Normal file
View file

@ -0,0 +1,19 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
interface Timer factory _Timer{
/*
* Creates a new timer. The [callback] callback is invoked after
* [milliSeconds] milliseconds. If [repeating] is set, the timer
* is repeated every [milliSeconds] milliseconds until cancelled.
*/
Timer(void callback(Timer timer), int milliSeconds, bool repeating);
/*
* Cancels the timer.
*/
void cancel();
}

162
runtime/bin/timer_impl.dart Normal file
View file

@ -0,0 +1,162 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
class _Timer implements Timer {
/*
* Set jitter to wake up timer events that would happen in _TIMER_JITTER ms.
*/
static final int _TIMER_JITTER = 0;
/*
* Disables the timer.
*/
static final int _NO_TIMER = -1;
factory _Timer(void callback(Timer timer),
int milliSeconds,
bool repeating) {
EventHandler._start();
if (_timers === null) {
_timers = new DoubleLinkedQueue<_Timer>();
}
Timer timer = new _Timer._internal();
timer._callback = callback;
timer._milliSeconds = milliSeconds;
timer._wakeupTime = (new DateTime.now()).value + milliSeconds;
timer._repeating = repeating;
timer._addTimerToList();
timer._notifyEventHandler();
return timer;
}
_Timer._internal() {}
void _clear() {
_callback = null;
_milliSeconds = 0;
_wakeupTime = 0;
_repeating = false;
}
/*
* Cancels a set timer. The timer is removed from the timer list and if
* the given timer is the earliest timer the native timer is reset.
*/
void cancel() {
_clear();
DoubleLinkedQueueEntry<_Timer> entry = _timers.firstEntry();
DoubleLinkedQueueEntry<_Timer> first = _timers.firstEntry();
while (entry !== null) {
if (entry.element === this) {
entry.remove();
if (first.element == this) {
entry = _timers.firstEntry();
_notifyEventHandler();
}
return;
}
entry = entry.nextEntry();
}
}
void _advanceWakeupTime() {
_wakeupTime += _milliSeconds;
}
/*
* Adds a timer to the timer list and resets the native timer if it is the
* earliest timer in the list. Timers with the same wakeup time are enqueued
* in order and notified in FIFO order.
*/
void _addTimerToList() {
if (_callback !== null) {
DoubleLinkedQueueEntry<_Timer> entry = _timers.firstEntry();
if (entry === null) {
_createTimerHandler();
}
while (entry !== null) {
if (_wakeupTime < entry.element._wakeupTime) {
entry.prepend(this);
return;
}
entry = entry.nextEntry();
}
_timers.addLast(this);
}
}
void _notifyEventHandler() {
if (_timers.firstEntry() === null) {
EventHandler._sendData(-1, _receivePort, _NO_TIMER);
_shutdownTimerHandler();
} else {
EventHandler._sendData(-1,
_receivePort,
_timers.firstEntry().element._wakeupTime);
}
}
/*
* Creates a receive port and registers the timer handler on that receive
* port.
*/
void _createTimerHandler() {
void _handleTimeout() {
int currentTime = (new DateTime.now()).value + _TIMER_JITTER;
DoubleLinkedQueueEntry<_Timer> entry = _timers.firstEntry();
DoubleLinkedQueueEntry<_Timer> current;
while (entry !== null) {
current = entry;
_Timer timer = current.element;
entry = entry.nextEntry();
if (timer._wakeupTime <= currentTime) {
current.remove();
(current.element._callback)(current.element);
if (current.element._repeating) {
current.element._advanceWakeupTime();
timer._addTimerToList();
_notifyEventHandler();
}
} else {
break;
}
}
_notifyEventHandler();
}
if(_receivePort === null) {
_receivePort = new ReceivePort();
_receivePort.receive((var message, ignored) {
_handleTimeout();
});
}
}
void _shutdownTimerHandler() {
_receivePort.close();
_receivePort = null;
}
/*
* Timers are ordered by wakeup time.
*/
static DoubleLinkedQueue<_Timer> _timers;
static ReceivePort _receivePort;
var _callback;
int _milliSeconds;
int _wakeupTime;
bool _repeating;
}

View file

@ -0,0 +1,4 @@
# This file is used by gcl to get repository specific information.
CODE_REVIEW_SERVER: https://chromereviews.googleplex.com
VIEW_VC: https://code.google.com/p/dart/source/detail?r=
CC_LIST:

33
runtime/dart-runtime.gyp Normal file
View file

@ -0,0 +1,33 @@
# Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
{
'includes': [
'vm/vm.gypi',
'bin/bin.gypi',
'third_party/jscre/jscre.gypi',
'tools/gyp/runtime-configurations.gypi',
],
'targets': [
{
'target_name': 'libdart',
'type': 'shared_library',
'dependencies': [
'libdart_lib',
'libdart_vm',
'libjscre',
],
'include_dirs': [
'.',
],
'defines': [
'DART_SHARED_LIB',
],
'sources': [
'include/dart_api.h',
'vm/dart_api_impl.cc',
],
},
],
}

395
runtime/include/dart_api.h Executable file
View file

@ -0,0 +1,395 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef INCLUDE_DART_API_H_
#define INCLUDE_DART_API_H_
#ifdef __cplusplus
#define DART_EXTERN_C extern "C"
#else
#define DART_EXTERN_C
#endif
#if defined(__CYGWIN__)
#error Tool chain and platform not supported.
#elif defined(_WIN32)
typedef signed __int8 int8_t;
typedef signed __int16 int16_t;
typedef signed __int32 int32_t;
typedef signed __int64 int64_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
#if defined(DART_SHARED_LIB)
#define DART_EXPORT DART_EXTERN_C __declspec(dllexport)
#else
#define DART_EXPORT DART_EXTERN_C
#endif
#else
#include <inttypes.h>
#if __GNUC__ >= 4
#if defined(DART_SHARED_LIB)
#define DART_EXPORT DART_EXTERN_C __attribute__ ((visibility("default")))
#else
#define DART_EXPORT DART_EXTERN_C
#endif
#else
#error Tool chain not supported.
#endif
#endif
#include <assert.h>
typedef void* Dart_Isolate;
typedef void* Dart_Handle;
typedef void* Dart_NativeArguments;
typedef enum {
kRetCIntptr = 0,
kRetCBool,
kRetCString,
kRetObject,
kRetCInt64,
kRetCDouble,
kRetLibSpec,
kRetError,
} Dart_ReturnType;
typedef struct {
Dart_ReturnType type_;
union {
intptr_t int_value;
bool bool_value;
const char* str_value;
Dart_Handle obj_value;
int64_t int64_value;
double double_value;
const char* errmsg;
} retval_;
} Dart_Result;
typedef enum {
kLibraryTag = 0,
kImportTag,
kSourceTag,
kCanonicalizeUrl,
} Dart_LibraryTag;
typedef void Dart_Snapshot;
typedef int64_t Dart_Port;
// Allow the embedder to intercept isolate creation. Both at startup and when
// spawning new isolates from Dart code.
// The result returned from this callback is handed to all isolates spawned
// from the isolate currently being initialized.
// Return NULL if an error is encountered. The isolate being initialized will
// be shutdown. No Dart code will execute in before it is shutdown.
// TODO(iposva): Pass a specification of the app file being spawned.
typedef void* (*Dart_IsolateInitCallback)(void* data);
typedef void (*Dart_NativeFunction)(Dart_NativeArguments arguments);
typedef Dart_NativeFunction (*Dart_NativeEntryResolver)(Dart_Handle name,
int num_of_arguments);
typedef Dart_Result (*Dart_LibraryTagHandler)(Dart_LibraryTag tag,
Dart_Handle library,
Dart_Handle url);
// TODO(iposva): This is a placeholder for the eventual external Dart API.
// Return value handling after a Dart API call.
inline bool Dart_IsValidResult(const Dart_Result& result) {
return (result.type_ != kRetError);
}
inline intptr_t Dart_GetResultAsCIntptr(const Dart_Result& result) {
assert(result.type_ == kRetCIntptr); // Valid to access result as C int.
return result.retval_.int_value;
}
inline Dart_Result Dart_ResultAsCIntptr(intptr_t value) {
Dart_Result result;
result.type_ = kRetCIntptr;
result.retval_.int_value = value;
return result;
}
inline bool Dart_GetResultAsCBoolean(const Dart_Result& result) {
assert(result.type_ == kRetCBool); // Valid to access result as C bool.
return result.retval_.bool_value;
}
inline Dart_Result Dart_ResultAsCBoolean(bool value) {
Dart_Result result;
result.type_ = kRetCBool;
result.retval_.bool_value = value;
return result;
}
inline const char* Dart_GetResultAsCString(const Dart_Result& result) {
assert(result.type_ == kRetCString); // Valid to access result as C string.
return result.retval_.str_value;
}
inline Dart_Result Dart_ResultAsCString(const char* value) {
// Assumes passed in string value will be available on return.
Dart_Result result;
result.type_ = kRetCString;
result.retval_.str_value = value;
return result;
}
inline Dart_Handle Dart_GetResult(const Dart_Result& result) {
assert(result.type_ == kRetObject); // Valid to access result as Dart obj.
return result.retval_.obj_value;
}
inline Dart_Result Dart_ResultAsObject(Dart_Handle value) {
Dart_Result result;
result.type_ = kRetObject;
result.retval_.obj_value = value;
return result;
}
inline int64_t Dart_GetResultAsCInt64(const Dart_Result& result) {
assert(result.type_ == kRetCInt64); // Valid to access result as C int64_t.
return result.retval_.int64_value;
}
inline Dart_Result Dart_ResultAsCInt64(int64_t value) {
Dart_Result result;
result.type_ = kRetCInt64;
result.retval_.int64_value = value;
return result;
}
inline double Dart_GetResultAsCDouble(const Dart_Result& result) {
assert(result.type_ == kRetCDouble); // Valid to access result as C double.
return result.retval_.double_value;
}
inline Dart_Result Dart_ResultAsCDouble(double value) {
Dart_Result result;
result.type_ = kRetCDouble;
result.retval_.double_value = value;
return result;
}
inline const char* Dart_GetErrorCString(const Dart_Result& result) {
assert(result.type_ == kRetError); // Valid to access only on failure.
return result.retval_.errmsg;
}
inline Dart_Result Dart_ErrorResult(const char* value) {
// Assumes passed in string value will be available on return.
Dart_Result result;
result.type_ = kRetError;
result.retval_.errmsg = value;
return result;
}
// Initialize the VM with commmand line flags.
DART_EXPORT bool Dart_Initialize(int argc, char** argv,
Dart_IsolateInitCallback callback);
// Isolate handling.
DART_EXPORT Dart_Isolate Dart_CreateIsolate(const Dart_Snapshot* snapshot,
void* data);
DART_EXPORT void Dart_ShutdownIsolate();
DART_EXPORT Dart_Isolate Dart_CurrentIsolate();
DART_EXPORT void Dart_EnterIsolate(Dart_Isolate isolate);
DART_EXPORT void Dart_ExitIsolate();
DART_EXPORT void Dart_RunLoop();
// Object.
DART_EXPORT Dart_Result Dart_ObjectToString(Dart_Handle object);
DART_EXPORT bool Dart_IsNull(Dart_Handle object);
// Returns true if the two objects are equal.
DART_EXPORT Dart_Result Dart_Objects_Equal(Dart_Handle obj1, Dart_Handle obj2);
// Classes.
DART_EXPORT Dart_Result Dart_GetClass(Dart_Handle library, Dart_Handle name);
DART_EXPORT Dart_Result Dart_IsInstanceOf(Dart_Handle object, Dart_Handle cls);
// Number.
DART_EXPORT bool Dart_IsNumber(Dart_Handle object);
// Integer.
DART_EXPORT bool Dart_IsInteger(Dart_Handle object);
DART_EXPORT Dart_Handle Dart_NewInteger(int64_t value);
DART_EXPORT Dart_Handle Dart_NewIntegerFromHexCString(const char* value);
DART_EXPORT Dart_Result Dart_IntegerValue(Dart_Handle integer);
DART_EXPORT Dart_Result Dart_IntegerFitsIntoInt64(Dart_Handle integer);
// Boolean.
DART_EXPORT bool Dart_IsBoolean(Dart_Handle object);
DART_EXPORT Dart_Handle Dart_NewBoolean(bool value);
DART_EXPORT Dart_Result Dart_BooleanValue(Dart_Handle bool_object);
// Double.
DART_EXPORT bool Dart_IsDouble(Dart_Handle object);
DART_EXPORT Dart_Handle Dart_NewDouble(double value);
DART_EXPORT Dart_Result Dart_DoubleValue(Dart_Handle integer);
// String.
DART_EXPORT bool Dart_IsString(Dart_Handle object);
DART_EXPORT Dart_Result Dart_StringLength(Dart_Handle str);
DART_EXPORT Dart_Handle Dart_NewString(const char* str);
DART_EXPORT Dart_Handle Dart_NewString8(const uint8_t* codepoints,
intptr_t length);
DART_EXPORT Dart_Handle Dart_NewString16(const uint16_t* codepoints,
intptr_t length);
DART_EXPORT Dart_Handle Dart_NewString32(const uint32_t* codepoints,
intptr_t length);
// The functions below test whether the object is a String and its codepoints
// all fit into 8 or 16 bits respectively.
DART_EXPORT bool Dart_IsString8(Dart_Handle object);
DART_EXPORT bool Dart_IsString16(Dart_Handle object);
DART_EXPORT Dart_Result Dart_StringGet8(Dart_Handle str,
uint8_t* codepoints,
intptr_t length);
DART_EXPORT Dart_Result Dart_StringGet16(Dart_Handle str,
uint16_t* codepoints,
intptr_t length);
DART_EXPORT Dart_Result Dart_StringGet32(Dart_Handle str,
uint32_t* codepoints,
intptr_t length);
DART_EXPORT Dart_Result Dart_StringToCString(Dart_Handle str);
// Array.
DART_EXPORT bool Dart_IsArray(Dart_Handle object);
DART_EXPORT Dart_Handle Dart_NewArray(intptr_t length);
DART_EXPORT Dart_Result Dart_GetLength(Dart_Handle array);
DART_EXPORT Dart_Result Dart_ArrayGetAt(Dart_Handle array,
intptr_t index);
DART_EXPORT Dart_Result Dart_ArrayGet(Dart_Handle array,
intptr_t offset,
uint8_t* native_array,
intptr_t length);
DART_EXPORT Dart_Result Dart_ArraySetAt(Dart_Handle array,
intptr_t index,
Dart_Handle value);
DART_EXPORT Dart_Result Dart_ArraySet(Dart_Handle array,
intptr_t offset,
uint8_t* native_array,
intptr_t length);
// Closure.
DART_EXPORT bool Dart_IsClosure(Dart_Handle object);
// DEPRECATED: The API below is a temporary hack.
DART_EXPORT Dart_Result Dart_ClosureSmrck(Dart_Handle object);
DART_EXPORT void Dart_ClosureSetSmrck(Dart_Handle object, int64_t value);
// Invocation of methods.
DART_EXPORT Dart_Result Dart_InvokeStatic(Dart_Handle library,
Dart_Handle class_name,
Dart_Handle function_name,
int number_of_arguments,
Dart_Handle* arguments);
DART_EXPORT Dart_Result Dart_InvokeDynamic(Dart_Handle receiver,
Dart_Handle function_name,
int number_of_arguments,
Dart_Handle* arguments);
DART_EXPORT Dart_Result Dart_InvokeClosure(Dart_Handle closure,
int number_of_arguments,
Dart_Handle* arguments);
// Interaction with native methods.
DART_EXPORT Dart_Handle Dart_GetNativeArgument(Dart_NativeArguments args,
int index);
DART_EXPORT void Dart_SetReturnValue(Dart_NativeArguments args,
Dart_Handle retval);
// Library.
DART_EXPORT bool Dart_IsLibrary(Dart_Handle object);
DART_EXPORT Dart_Result Dart_LibraryUrl(Dart_Handle library);
DART_EXPORT Dart_Result Dart_LibraryImportLibrary(Dart_Handle library,
Dart_Handle import);
DART_EXPORT Dart_Result Dart_LookupLibrary(Dart_Handle url);
DART_EXPORT Dart_Result Dart_LoadLibrary(Dart_Handle url,
Dart_Handle source);
DART_EXPORT Dart_Result Dart_LoadSource(Dart_Handle library,
Dart_Handle url,
Dart_Handle source);
DART_EXPORT Dart_Result Dart_SetNativeResolver(
Dart_Handle library,
Dart_NativeEntryResolver resolver);
// Script handling.
DART_EXPORT Dart_Result Dart_LoadScript(Dart_Handle url,
Dart_Handle source,
Dart_LibraryTagHandler handler);
// Compile all loaded classes and functions eagerly.
DART_EXPORT Dart_Result Dart_CompileAll();
// Exception related.
DART_EXPORT bool Dart_ExceptionOccurred(Dart_Handle result);
DART_EXPORT Dart_Result Dart_GetException(Dart_Handle result);
DART_EXPORT Dart_Result Dart_GetStacktrace(Dart_Handle unhandled_exception);
DART_EXPORT Dart_Result Dart_ThrowException(Dart_Handle exception);
DART_EXPORT Dart_Result Dart_ReThrowException(Dart_Handle exception,
Dart_Handle stacktrace);
// Global Handles and Scope for local handles and zone based memory allocation.
DART_EXPORT void Dart_EnterScope();
DART_EXPORT void Dart_ExitScope();
DART_EXPORT Dart_Handle Dart_NewPersistentHandle(Dart_Handle object);
DART_EXPORT Dart_Handle Dart_MakeWeakPersistentHandle(Dart_Handle object);
DART_EXPORT Dart_Handle Dart_MakePersistentHandle(Dart_Handle object);
DART_EXPORT void Dart_DeletePersistentHandle(Dart_Handle object);
// Fields.
DART_EXPORT Dart_Result Dart_GetStaticField(Dart_Handle cls, Dart_Handle name);
DART_EXPORT Dart_Result Dart_SetStaticField(Dart_Handle cls,
Dart_Handle name,
Dart_Handle value);
DART_EXPORT Dart_Result Dart_GetInstanceField(Dart_Handle obj,
Dart_Handle name);
DART_EXPORT Dart_Result Dart_SetInstanceField(Dart_Handle obj,
Dart_Handle name,
Dart_Handle value);
// Native fields.
DART_EXPORT Dart_Result Dart_CreateNativeWrapperClass(Dart_Handle library,
Dart_Handle class_name,
int field_count);
DART_EXPORT Dart_Result Dart_GetNativeInstanceField(Dart_Handle obj,
int index);
DART_EXPORT Dart_Result Dart_SetNativeInstanceField(Dart_Handle obj,
int index,
intptr_t value);
// Snapshot creation.
DART_EXPORT Dart_Result Dart_CreateSnapshot(uint8_t** snaphot_buffer,
intptr_t* snapshot_size);
// Message communication.
DART_EXPORT Dart_Result Dart_PostIntArray(Dart_Port port,
int field_count,
intptr_t* data);
DART_EXPORT Dart_Result Dart_Post(Dart_Port port, Dart_Handle value);
// External pprof support for gathering and dumping symbolic information
// that can be used for better profile reports for dynamically generated
// code.
DART_EXPORT void Dart_InitPprofSupport();
DART_EXPORT void Dart_GetPprofSymbolInfo(void** buffer, int* buffer_size);
// Check set vm flags.
DART_EXPORT bool Dart_IsVMFlagSet(const char* flag_name);
#endif // INCLUDE_DART_API_H_

142
runtime/lib/array.cc Normal file
View file

@ -0,0 +1,142 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/bootstrap_natives.h"
#include "vm/assembler.h"
#include "vm/assert.h"
#include "vm/bigint_operations.h"
#include "vm/exceptions.h"
#include "vm/native_entry.h"
#include "vm/object.h"
namespace dart {
DEFINE_NATIVE_ENTRY(ObjectArray_allocate, 2) {
const TypeArguments& type_arguments =
TypeArguments::CheckedHandle(arguments->At(0));
const Instance& length_instance = Instance::CheckedHandle(arguments->At(1));
if (!length_instance.IsSmi()) {
GrowableArray<const Object*> args;
args.Add(&length_instance);
Exceptions::ThrowByType(Exceptions::kIllegalArgument, args);
}
Smi& length = Smi::Handle();
length ^= length_instance.raw();
ASSERT(type_arguments.IsNull() ||
(type_arguments.IsInstantiated() && (type_arguments.Length() == 1)));
if (length.IsNull() || (length.Value() < 0)) {
GrowableArray<const Object*> args;
args.Add(&length);
Exceptions::ThrowByType(Exceptions::kIllegalArgument, args);
}
const Array& new_array = Array::Handle(Array::New(length.Value()));
new_array.SetTypeArguments(type_arguments);
arguments->SetReturn(new_array);
}
DEFINE_NATIVE_ENTRY(ObjectArray_getIndexed, 2) {
const Array& array = Array::CheckedHandle(arguments->At(0));
const Instance& index_instance = Instance::CheckedHandle(arguments->At(1));
if (!index_instance.IsSmi()) {
GrowableArray<const Object*> args;
args.Add(&index_instance);
Exceptions::ThrowByType(Exceptions::kIllegalArgument, args);
}
Smi& index = Smi::Handle();
index ^= index_instance.raw();
if (array.IsNull() || index.IsNull()) {
// TODO(asiva): Need to handle error cases.
UNIMPLEMENTED();
return;
}
if ((index.Value() < 0) || (index.Value() >= array.Length())) {
GrowableArray<const Object*> arguments;
arguments.Add(&index);
Exceptions::ThrowByType(Exceptions::kIndexOutOfRange, arguments);
}
const Instance& obj = Instance::CheckedHandle(array.At(index.Value()));
arguments->SetReturn(obj);
}
DEFINE_NATIVE_ENTRY(ObjectArray_setIndexed, 3) {
const Array& array = Array::CheckedHandle(arguments->At(0));
const Smi& index = Smi::CheckedHandle(arguments->At(1));
const Instance& value = Instance::CheckedHandle(arguments->At(2));
if (array.IsNull() || index.IsNull()) {
// TODO(asiva): Need to handle error cases.
UNIMPLEMENTED();
return;
}
if ((index.Value() < 0) || (index.Value() >= array.Length())) {
GrowableArray<const Object*> arguments;
arguments.Add(&index);
Exceptions::ThrowByType(Exceptions::kIndexOutOfRange, arguments);
}
array.SetAt(index.Value(), value);
}
DEFINE_NATIVE_ENTRY(ObjectArray_getLength, 1) {
const Array& array = Array::CheckedHandle(arguments->At(0));
if (array.IsNull()) {
// TODO(asiva): Need to handle error cases.
UNIMPLEMENTED();
return;
}
const Smi& length = Smi::Handle(Smi::New(array.Length()));
arguments->SetReturn(length);
}
// ObjectArray src, int srcStart, int dstStart, int count.
DEFINE_NATIVE_ENTRY(ObjectArray_copyFromObjectArray, 5) {
const Array& dest = Array::CheckedHandle(arguments->At(0));
const Array& source = Array::CheckedHandle(arguments->At(1));
const Smi& src_start = Smi::CheckedHandle(arguments->At(2));
const Smi& dst_start = Smi::CheckedHandle(arguments->At(3));
const Smi& count = Smi::CheckedHandle(arguments->At(4));
if (dest.IsNull() || source.IsNull() || src_start.IsNull() ||
dst_start.IsNull() || count.IsNull()) {
GrowableArray<const Object*> args;
Exceptions::ThrowByType(Exceptions::kIllegalArgument, args);
}
intptr_t icount = count.Value();
if (icount < 0) {
GrowableArray<const Object*> args;
Exceptions::ThrowByType(Exceptions::kIllegalArgument, args);
}
if (icount == 0) {
return;
}
intptr_t isrc_start = src_start.Value();
intptr_t idst_start = dst_start.Value();
if ((isrc_start + icount) > source.Length()) {
GrowableArray<const Object*> arguments;
arguments.Add(&src_start);
Exceptions::ThrowByType(Exceptions::kIndexOutOfRange, arguments);
}
if ((idst_start + icount) > dest.Length()) {
GrowableArray<const Object*> arguments;
arguments.Add(&dst_start);
Exceptions::ThrowByType(Exceptions::kIndexOutOfRange, arguments);
}
Object& src_obj = Object::Handle();
if (isrc_start < idst_start) {
for (intptr_t i = icount - 1; i >= 0; i--) {
src_obj = source.At(isrc_start + i);
dest.SetAt(idst_start + i, src_obj);
}
} else {
for (intptr_t i = 0; i < icount; i++) {
src_obj = source.At(isrc_start + i);
dest.SetAt(idst_start + i, src_obj);
}
}
}
} // namespace dart

294
runtime/lib/array.dart Normal file
View file

@ -0,0 +1,294 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
class ArrayFactory<T> {
factory Array.from(Iterable<T> other) {
GrowableObjectArray<T> array = new GrowableObjectArray<T>();
for (final e in other) {
array.add(e);
}
return array;
}
factory Array.fromArray(Array<T> other, int startIndex, int endIndex) {
Array array = new Array<T>();
if (endIndex > other.length) endIndex = other.length;
if (startIndex < 0) startIndex = 0;
int count = endIndex - startIndex;
if (count > 0) {
array.length = count;
Arrays.copy(other, startIndex, array, 0, count);
}
return array;
}
factory Array([int length = null]) {
if (length === null) {
return new GrowableObjectArray<T>();
} else {
return new ObjectArray<T>(length);
}
}
}
class ListFactory<T> {
factory List.from(Iterable<T> other) {
GrowableObjectArray<T> list = new GrowableObjectArray<T>();
for (final e in other) {
list.add(e);
}
return list;
}
factory List.fromList(List<T> other, int startIndex, int endIndex) {
List list = new List<T>();
if (endIndex > other.length) endIndex = other.length;
if (startIndex < 0) startIndex = 0;
int count = endIndex - startIndex;
if (count > 0) {
list.length = count;
Arrays.copy(other, startIndex, list, 0, count);
}
return list;
}
factory List([int length = null]) {
if (length === null) {
return new GrowableObjectArray<T>();
} else {
return new ObjectArray<T>(length);
}
}
}
// TODO(srdjan): Use shared array implementation.
class ObjectArray<T> implements Array<T> {
factory ObjectArray(int length) native "ObjectArray_allocate";
T operator [](int index) native "ObjectArray_getIndexed";
void operator []=(int index, T value) native "ObjectArray_setIndexed";
String toString() {
return Arrays.asString(this);
}
int get length() native "ObjectArray_getLength";
void copyFrom(Array src, int srcStart, int dstStart, int count) {
if (src is ObjectArray) {
_copyFromObjectArray(src, srcStart, dstStart, count);
} else {
Arrays.copy(src, srcStart, this, dstStart, count);
}
}
void _copyFromObjectArray(ObjectArray src,
int srcStart,
int dstStart,
int count)
native "ObjectArray_copyFromObjectArray";
/**
* Collection interface.
*/
void forEach(f(T element)) {
Collections.forEach(this, f);
}
Collection<T> filter(bool f(T element)) {
return Collections.filter(this, new GrowableObjectArray<T>(), f);
}
bool every(bool f(T element)) {
return Collections.every(this, f);
}
bool some(bool f(T element)) {
return Collections.some(this, f);
}
bool isEmpty() {
return this.length === 0;
}
void sort(int compare(T a, T b)) {
DualPivotQuicksort.sort(this, compare);
}
int indexOf(T element, int startIndex) {
return Arrays.indexOf(this, element, startIndex, this.length);
}
int lastIndexOf(T element, int startIndex) {
return Arrays.lastIndexOf(this, element, startIndex);
}
Iterator<T> iterator() {
return new FixedSizeArrayIterator<T>(this);
}
void add(T element) {
throw const UnsupportedOperationException(
"Cannot add to a non-extendable array");
}
void addLast(T element) {
add(element);
}
void addAll(Collection<T> elements) {
throw const UnsupportedOperationException(
"Cannot add to a non-extendable array");
}
void clear() {
throw const UnsupportedOperationException(
"Cannot clear a non-extendable array");
}
void set length(int length) {
throw const UnsupportedOperationException(
"Cannot change the length of a non-extendable array");
}
T removeLast() {
throw const UnsupportedOperationException(
"Cannot remove in a non-extendable array");
}
T last() {
return this[length - 1];
}
}
// This is essentially the same class as ObjectArray, but it does not
// permit any modification of array elements from Dart code. We use
// this class for arrays constructed from Dart array literals.
// TODO(hausner): We should consider the trade-offs between two
// classes (and inline cache misses) versus a field in the native
// implementation (checks when modifying). We should keep watching
// the inline cache misses.
class ImmutableArray<T> implements Array<T> {
T operator [](int index) native "ObjectArray_getIndexed";
void operator []=(int index, T value) {
throw const UnsupportedOperationException(
"Cannot modify an immutable array");
}
int get length() native "ObjectArray_getLength";
void copyFrom(Array src, int srcStart, int dstStart, int count) {
throw const UnsupportedOperationException(
"Cannot modify an immutable array");
}
/**
* Collection interface.
*/
void forEach(f(T element)) {
Collections.forEach(this, f);
}
Collection<T> filter(bool f(T element)) {
return Collections.filter(this, new GrowableObjectArray<T>(), f);
}
bool every(bool f(T element)) {
return Collections.every(this, f);
}
bool some(bool f(T element)) {
return Collections.some(this, f);
}
bool isEmpty() {
return this.length === 0;
}
void sort(int compare(T a, T b)) {
throw const UnsupportedOperationException(
"Cannot modify an immutable array");
}
String toString() {
return "ImmutableArray";
}
int indexOf(T element, int startIndex) {
return Arrays.indexOf(this, element, startIndex, this.length);
}
int lastIndexOf(T element, int startIndex) {
return Arrays.lastIndexOf(this, element, startIndex);
}
Iterator<T> iterator() {
return new FixedSizeArrayIterator<T>(this);
}
void add(T element) {
throw const UnsupportedOperationException(
"Cannot add to an immutable array");
}
void addLast(T element) {
add(element);
}
void addAll(Collection<T> elements) {
throw const UnsupportedOperationException(
"Cannot add to an immutable array");
}
void clear() {
throw const UnsupportedOperationException(
"Cannot clear an immutable array");
}
void set length(int length) {
throw const UnsupportedOperationException(
"Cannot change the length of an immutable array");
}
T removeLast() {
throw const UnsupportedOperationException(
"Cannot remove in a non-extendable array");
}
T last() {
return this[length - 1];
}
}
// Iterator for arrays with fixed size.
class FixedSizeArrayIterator<T> implements Iterator<T> {
FixedSizeArrayIterator(Array array)
: _array = array, _length = array.length, _pos = 0 {
assert(array is ObjectArray || array is ImmutableArray);
}
bool hasNext() {
return _length > _pos;
}
T next() {
if (!hasNext()) {
throw const NoMoreElementsException();
}
return _array[_pos++];
}
final Array<T> _array;
final int _length; // Cache array length for faster access.
int _pos;
}

90
runtime/lib/arrays.dart Normal file
View file

@ -0,0 +1,90 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
class Arrays {
static String asString(Array array) {
String result = "[";
int len = array.length;
for (int i = 0; i < len; i++) {
// TODO(4466785): Deal with recursion and formatting.
result += array[i].toString() + ", ";
}
result += "]";
return result;
}
static void copy(Array src, int srcStart,
Array dst, int dstStart, int count) {
if (srcStart === null) srcStart = 0;
if (dstStart === null) dstStart = 0;
if (srcStart < dstStart) {
for (int i = srcStart + count - 1, j = dstStart + count - 1;
i >= srcStart; i--, j--) {
dst[j] = src[i];
}
} else {
for (int i = srcStart, j = dstStart; i < srcStart + count; i++, j++) {
dst[j] = src[i];
}
}
}
static bool areEqual(Array a, Object b) {
if (a === b) return true;
if (!(b is Array)) return false;
int length = a.length;
if (length != b.length) return false;
for (int i = 0; i < length; i++) {
if (a[i] !== b[i]) return false;
}
return true;
}
/**
* Returns the index in the array [a] of the given [element], starting
* the search at index [startIndex] to [endIndex] (exclusive).
* Returns -1 if [element] is not found.
*/
static int indexOf(Array a,
Object element,
int startIndex,
int endIndex) {
if (startIndex >= a.length) {
return -1;
}
if (startIndex < 0) {
startIndex = 0;
}
for (int i = startIndex; i < endIndex; i++) {
if (a[i] == element) {
return i;
}
}
return -1;
}
/**
* Returns the last index in the array [a] of the given [element], starting
* the search at index [startIndex] to 0.
* Returns -1 if [element] is not found.
*/
static int lastIndexOf(Array a, Object element, int startIndex) {
if (startIndex < 0) {
return -1;
}
if (startIndex >= a.length) {
startIndex = a.length - 1;
}
for (int i = startIndex; i >= 0; i--) {
if (a[i] == element) {
return i;
}
}
return -1;
}
}

6
runtime/lib/bool.dart Normal file
View file

@ -0,0 +1,6 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
class Bool implements bool {
}

26
runtime/lib/clock.cc Normal file
View file

@ -0,0 +1,26 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/bootstrap_natives.h"
#include "vm/object.h"
#include "vm/os.h"
namespace dart {
DEFINE_NATIVE_ENTRY(Clock_now, 0) {
// TODO(iposva): investigate other hi-res time sources such as cycle count.
const Integer& micros =
Integer::Handle(Integer::New(OS::GetCurrentTimeMicros()));
arguments->SetReturn(micros);
}
DEFINE_NATIVE_ENTRY(Clock_frequency, 0) {
// TODO(iposva): investigate other hi-res time sources such as cycle count.
const Integer& frequency = Integer::Handle(Integer::New(1000000));
arguments->SetReturn(frequency);
}
} // namespace dart

21
runtime/lib/clock.dart Normal file
View file

@ -0,0 +1,21 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/**
* The class [Clock] provides access to a monotonically incrementing clock
* device.
*/
class Clock {
/**
* Returns the current clock tick.
*/
static int now() native "Clock_now";
/**
* Returns the frequency of clock ticks in Hz.
*/
static int frequency() native "Clock_frequency";
}

View file

@ -0,0 +1,43 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/**
* The [Collections] class implements static methods useful when
* writing a class that implements [Collection] and the [iterator]
* method.
*/
class Collections {
static void forEach(Iterable<Object> iterable, void f(Object o)) {
for (final e in iterable) {
f(e);
}
}
static bool some(Iterable<Object> iterable, bool f(Object o)) {
for (final e in iterable) {
if (f(e)) return true;
}
return false;
}
static bool every(Iterable<Object> iterable, bool f(Object o)) {
for (final e in iterable) {
if (!f(e)) return false;
}
return true;
}
static List<Object> filter(Iterable<Object> source,
List<Object> destination,
bool f(Object o)) {
for (final e in source) {
if (f(e)) destination.add(e);
}
return destination;
}
static bool isEmpty(Iterable<Object> iterable) {
return !iterable.iterator().hasNext();
}
}

155
runtime/lib/date_time.cc Normal file
View file

@ -0,0 +1,155 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/bootstrap_natives.h"
#include "vm/bigint_operations.h"
#include "vm/native_entry.h"
#include "vm/object.h"
#include "vm/os.h"
namespace dart {
static bool BreakDownSecondsSinceEpoch(const Integer& dart_seconds,
const Bool& dart_is_utc,
OS::BrokenDownDateTime* result) {
bool is_utc = dart_is_utc.value();
int64_t value = dart_seconds.AsInt64Value();
time_t seconds = static_cast<time_t>(value);
return OS::BreakDownSecondsSinceEpoch(seconds, is_utc, result);
}
DEFINE_NATIVE_ENTRY(DateTimeNatives_brokenDownToSecondsSinceEpoch, 7) {
const Integer& dart_years = Integer::CheckedHandle(arguments->At(0));
const Smi& dart_month = Smi::CheckedHandle(arguments->At(1));
const Smi& dart_day = Smi::CheckedHandle(arguments->At(2));
const Smi& dart_hours = Smi::CheckedHandle(arguments->At(3));
const Smi& dart_minutes = Smi::CheckedHandle(arguments->At(4));
const Smi& dart_seconds = Smi::CheckedHandle(arguments->At(5));
const Bool& dart_is_utc = Bool::CheckedHandle(arguments->At(6));
if (!dart_years.IsSmi()) {
UNIMPLEMENTED();
}
Smi& smi_years = Smi::Handle();
smi_years ^= dart_years.raw();
OS::BrokenDownDateTime broken_down;
// mktime takes the years since 1900.
// TODO(floitsch): Removing 1900 could underflow the intptr_t.
intptr_t year = smi_years.Value() - 1900;
// TODO(floitsch): We don't handle the case yet where intptr_t and int have
// different sizes.
ASSERT(sizeof(year) <= sizeof(broken_down.year));
broken_down.year = year;
// libc months are 0-based (contrary to Dart' 1-based months).
broken_down.month = dart_month.Value() - 1;
broken_down.day = dart_day.Value();
broken_down.hours = dart_hours.Value();
broken_down.minutes = dart_minutes.Value();
broken_down.seconds = dart_seconds.Value();
time_t value;
bool succeeded = OS::BrokenDownToSecondsSinceEpoch(broken_down,
dart_is_utc.value(),
&value);
if (!succeeded) {
UNIMPLEMENTED();
}
arguments->SetReturn(Integer::Handle(Integer::New(value)));
}
DEFINE_NATIVE_ENTRY(DateTimeNatives_currentTimeMillis, 0) {
const Integer& time = Integer::Handle(
Integer::New(OS::GetCurrentTimeMillis()));
arguments->SetReturn(time);
}
DEFINE_NATIVE_ENTRY(DateTimeNatives_getYear, 2) {
const Integer& dart_seconds = Integer::CheckedHandle(arguments->At(0));
const Bool& dart_is_utc = Bool::CheckedHandle(arguments->At(1));
OS::BrokenDownDateTime broken_down;
bool succeeded =
BreakDownSecondsSinceEpoch(dart_seconds, dart_is_utc, &broken_down);
if (!succeeded) {
UNIMPLEMENTED();
}
// C uses years since 1900, and not full years.
// TODO(floitsch): adding 1900 could overflow the intptr_t.
intptr_t year = broken_down.year + 1900;
arguments->SetReturn(Integer::Handle(Integer::New(year)));
}
DEFINE_NATIVE_ENTRY(DateTimeNatives_getMonth, 2) {
const Integer& dart_seconds = Integer::CheckedHandle(arguments->At(0));
const Bool& dart_is_utc = Bool::CheckedHandle(arguments->At(1));
OS::BrokenDownDateTime broken_down;
bool succeeded =
BreakDownSecondsSinceEpoch(dart_seconds, dart_is_utc, &broken_down);
if (!succeeded) {
UNIMPLEMENTED();
}
// Dart has 1-based months (contrary to C's 0-based).
const Smi& result = Smi::Handle(Smi::New(broken_down.month + 1));
arguments->SetReturn(result);
}
DEFINE_NATIVE_ENTRY(DateTimeNatives_getDay, 2) {
const Integer& dart_seconds = Integer::CheckedHandle(arguments->At(0));
const Bool& dart_is_utc = Bool::CheckedHandle(arguments->At(1));
OS::BrokenDownDateTime broken_down;
bool succeeded =
BreakDownSecondsSinceEpoch(dart_seconds, dart_is_utc, &broken_down);
if (!succeeded) {
UNIMPLEMENTED();
}
const Smi& result = Smi::Handle(Smi::New(broken_down.day));
arguments->SetReturn(result);
}
DEFINE_NATIVE_ENTRY(DateTimeNatives_getHours, 2) {
const Integer& dart_seconds = Integer::CheckedHandle(arguments->At(0));
const Bool& dart_is_utc = Bool::CheckedHandle(arguments->At(1));
OS::BrokenDownDateTime broken_down;
bool succeeded =
BreakDownSecondsSinceEpoch(dart_seconds, dart_is_utc, &broken_down);
if (!succeeded) {
UNIMPLEMENTED();
}
const Smi& result = Smi::Handle(Smi::New(broken_down.hours));
arguments->SetReturn(result);
}
DEFINE_NATIVE_ENTRY(DateTimeNatives_getMinutes, 2) {
const Integer& dart_seconds = Integer::CheckedHandle(arguments->At(0));
const Bool& dart_is_utc = Bool::CheckedHandle(arguments->At(1));
OS::BrokenDownDateTime broken_down;
bool succeeded =
BreakDownSecondsSinceEpoch(dart_seconds, dart_is_utc, &broken_down);
if (!succeeded) {
UNIMPLEMENTED();
}
const Smi& result = Smi::Handle(Smi::New(broken_down.minutes));
arguments->SetReturn(result);
}
DEFINE_NATIVE_ENTRY(DateTimeNatives_getSeconds, 2) {
const Integer& dart_seconds = Integer::CheckedHandle(arguments->At(0));
const Bool& dart_is_utc = Bool::CheckedHandle(arguments->At(1));
OS::BrokenDownDateTime broken_down;
bool succeeded =
BreakDownSecondsSinceEpoch(dart_seconds, dart_is_utc, &broken_down);
if (!succeeded) {
UNIMPLEMENTED();
}
const Smi& result = Smi::Handle(Smi::New(broken_down.seconds));
arguments->SetReturn(result);
}
} // namespace dart

424
runtime/lib/date_time.dart Normal file
View file

@ -0,0 +1,424 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Dart core library.
class TimeZoneImplementation implements TimeZone {
Time get offset() {
if (isUtc) return const Time.duration(0);
throw "Unimplemented";
}
factory TimeZoneImplementation(Time offset) {
if (offset.duration == 0) {
return const TimeZoneImplementation.utc();
} else {
throw "Unimplemented";
}
}
const TimeZoneImplementation.utc() : isUtc = true;
TimeZoneImplementation.local() : isUtc = false {}
bool operator ==(Object other) {
if (!(other is TimeZoneImplementation)) return false;
return isUtc == other.isUtc;
}
final bool isUtc;
}
// JavaScript implementation of DateTimeImplementation.
class DateTimeImplementation implements DateTime {
factory DateTimeImplementation(int years,
int month,
int day,
int hours,
int minutes,
int seconds,
int milliseconds) {
return new DateTimeImplementation.withTimeZone(
years, month, day,
hours, minutes, seconds, milliseconds,
new TimeZoneImplementation.local());
}
DateTimeImplementation.withTimeZone(int years,
int month,
int day,
int hours,
int minutes,
int seconds,
int milliseconds,
TimeZoneImplementation timeZone)
: timeZone = timeZone,
value = brokenDownDateTimeToMillisecondsSinceEpoch_(
years, month, day, hours, minutes, seconds, milliseconds,
timeZone.isUtc) {}
factory DateTimeImplementation.fromDateAndTime(
Date date,
Time time,
TimeZoneImplementation timeZone) {
if (timeZone === null) {
timeZone = new TimeZoneImplementation.local();
}
return new DateTimeImplementation.withTimeZone(date.year,
date.month,
date.day + time.days,
time.hours,
time.minutes,
time.seconds,
time.milliseconds,
timeZone);
}
DateTimeImplementation.now()
: timeZone = new TimeZone.local(),
value = getCurrentMs_() {
}
factory DateTimeImplementation.fromString(String formattedString) {
int substringToNumber(String str, int from, int to) {
int result = 0;
for (int i = from; i < to; i++) {
result = result * 10 + str.charCodeAt(i) - "0".charCodeAt(0);
}
return result;
}
// TODO(floitsch): improve DateTimeImplementation parsing.
// Parse ISO 8601: "2011-05-14 00:37:18.231Z".
int yearMonthSeparator = formattedString.indexOf("-", 0);
if (yearMonthSeparator < 0) throw "UNIMPLEMENTED";
int monthDaySeparator =
formattedString.indexOf("-", yearMonthSeparator + 1);
if (monthDaySeparator < 0) throw "UNIMPLEMENTED";
int dateTimeSeparator = formattedString.indexOf(" ", monthDaySeparator + 1);
if (dateTimeSeparator < 0) throw "UNIMPLEMENTED";
int hoursMinutesSeparator =
formattedString.indexOf(":", dateTimeSeparator + 1);
if (hoursMinutesSeparator < 0) throw "UNIMPLEMENTED";
int minutesSecondsSeparator =
formattedString.indexOf(":", hoursMinutesSeparator + 1);
if (minutesSecondsSeparator < 0) throw "UNIMPLEMENTED";
int secondsMillisecondsSeparator =
formattedString.indexOf(".", minutesSecondsSeparator + 1);
bool isUtc = formattedString.endsWith("Z");
int end = formattedString.length - (isUtc ? 1 : 0);
if (secondsMillisecondsSeparator < 0) secondsMillisecondsSeparator = end;
int year = substringToNumber(formattedString, 0, yearMonthSeparator);
int month = substringToNumber(formattedString,
yearMonthSeparator + 1,
monthDaySeparator);
int day = substringToNumber(formattedString,
monthDaySeparator + 1,
dateTimeSeparator);
int hours = substringToNumber(formattedString,
dateTimeSeparator + 1,
hoursMinutesSeparator);
int minutes = substringToNumber(formattedString,
hoursMinutesSeparator + 1,
minutesSecondsSeparator);
int seconds = substringToNumber(formattedString,
minutesSecondsSeparator + 1,
secondsMillisecondsSeparator);
int milliseconds = substringToNumber(formattedString,
secondsMillisecondsSeparator + 1,
end);
TimeZone timeZone = (isUtc ? const TimeZone.utc() : new TimeZone.local());
return new DateTimeImplementation.withTimeZone(
year, month, day, hours, minutes, seconds, milliseconds, timeZone);
}
const DateTimeImplementation.fromEpoch(int this.value,
TimeZone this.timeZone);
bool operator ==(Object other) {
if (!(other is DateTimeImplementation)) return false;
return value == other.value && timeZone == other.timeZone;
}
int compareTo(DateTime other) {
return value.compareTo(other.value);
}
DateTime changeTimeZone(TimeZone targetTimeZone) {
if (targetTimeZone === null) {
targetTimeZone = new TimeZoneImplementation.local();
}
return new DateTime.fromEpoch(value, targetTimeZone);
}
Date get date() {
return new DateImplementation(year, month, day);
}
Time get time() {
return new TimeImplementation(0, hours, minutes, seconds, milliseconds);
}
int get year() {
int secondsSinceEpoch = secondsSinceEpoch_;
// According to V8 some library calls have troubles with negative values.
// Therefore clamp to 0 - year 2035 (which is less than the size of 32bit).
if (secondsSinceEpoch >= 0 && secondsSinceEpoch < SECONDS_YEAR_2035_) {
return getYear_(secondsSinceEpoch, timeZone.isUtc);
}
// Approximate the result. We don't take timeZone into account.
int approximateYear = yearsFromSecondsSinceEpoch_(secondsSinceEpoch);
int equivalentYear = equivalentYear_(approximateYear);
int y = getYear_(equivalentSeconds_(secondsSinceEpoch_), timeZone.isUtc);
return approximateYear + (y - equivalentYear);
}
int get month() {
return getMonth_(equivalentSeconds_(secondsSinceEpoch_), timeZone.isUtc);
}
int get day() {
return getDay_(equivalentSeconds_(secondsSinceEpoch_), timeZone.isUtc);
}
int get hours() {
return getHours_(equivalentSeconds_(secondsSinceEpoch_), timeZone.isUtc);
}
int get minutes() {
return getMinutes_(equivalentSeconds_(secondsSinceEpoch_), timeZone.isUtc);
}
int get seconds() {
return getSeconds_(equivalentSeconds_(secondsSinceEpoch_), timeZone.isUtc);
}
int get milliseconds() {
return value % Time.MS_PER_SECOND;
}
int get secondsSinceEpoch_() {
// Always round down.
if (value < 0) {
return (value + 1) ~/ Time.MS_PER_SECOND - 1;
} else {
return value ~/ Time.MS_PER_SECOND;
}
}
int get weekday() {
throw "Unimplemented";
}
bool isLocalTime() {
return !timeZone.isUtc;
}
bool isUtc() {
return timeZone.isUtc;
}
String toString() {
// TODO(floitsch): switch to string-interpolation.
if (timeZone.isUtc) {
return date.toString() + " " + time.toString() + "Z";
} else {
return date.toString() + " " + time.toString();
}
}
// Adds the duration [time] to this DateTime instance.
DateTime add(Time time) {
return new DateTimeImplementation.fromEpoch(value + time.duration,
timeZone);
}
// Subtracts the duration [time] from this DateTime instance.
DateTime subtract(Time time) {
return new DateTimeImplementation.fromEpoch(value - time.duration,
timeZone);
}
// Returns a [Time] with the difference of [this] and [other].
Time difference(DateTime other) {
return new TimeImplementation.duration(value - other.value);
}
final int value;
final TimeZoneImplementation timeZone;
static final int SECONDS_YEAR_2035_ = 2051222400;
// Returns the UTC year for the corresponding [secondsSinceEpoch].
// It is relatively fast for values in the range 0 to year 2098.
// Code is adapted from V8.
static int yearsFromSecondsSinceEpoch_(int secondsSinceEpoch) {
final int DAYS_IN_4_YEARS = 4 * 365 + 1;
final int DAYS_IN_100_YEARS = 25 * DAYS_IN_4_YEARS - 1;
final int DAYS_IN_400_YEARS = 4 * DAYS_IN_100_YEARS + 1;
final int DAYS_1970_TO_2000 = 30 * 365 + 7;
final int DAYS_OFFSET = 1000 * DAYS_IN_400_YEARS + 5 * DAYS_IN_400_YEARS -
DAYS_1970_TO_2000;
final int YEARS_OFFSET = 400000;
final int DAYS_YEAR_2098 = DAYS_IN_100_YEARS + 6 * DAYS_IN_4_YEARS;
int days = secondsSinceEpoch ~/ Time.SECONDS_PER_DAY;
if (days > 0 && days < DAYS_YEAR_2098) {
// According to V8 this fast case works for dates from 1970 to 2099.
return 1970 + (4 * days + 2) ~/ DAYS_IN_4_YEARS;
} else {
days += DAYS_OFFSET;
int result = 400 * (days ~/ DAYS_IN_400_YEARS) - YEARS_OFFSET;
days = days.remainder(DAYS_IN_400_YEARS);
days--;
int yd1 = days ~/ DAYS_IN_100_YEARS;
days = days.remainder(DAYS_IN_100_YEARS);
result += 100 * yd1;
days++;
int yd2 = days ~/ DAYS_IN_4_YEARS;
days = days.remainder(DAYS_IN_4_YEARS);
result += 4 * yd2;
days--;
int yd3 = days ~/ 365;
days = days.remainder(365);
result += yd3;
return result;
}
}
// Given [secondsSinceEpoch] returns seconds such that they are at the same
// time in an equivalent year (see [equivalentYear_]).
// Leap seconds are ignored.
static int equivalentSeconds_(int secondsSinceEpoch) {
if (secondsSinceEpoch >= 0 && secondsSinceEpoch < SECONDS_YEAR_2035_) {
return secondsSinceEpoch;
}
int year = yearsFromSecondsSinceEpoch_(secondsSinceEpoch);
int days = dayFromYear_(year);
int equivalentYear = equivalentYear_(year);
int equivalentDays = dayFromYear_(equivalentYear);
int diffDays = equivalentDays - days;
return secondsSinceEpoch + diffDays * Time.SECONDS_PER_DAY;
}
// Returns the days since 1970 for the start of the given [year].
// [year] may be before epoch.
static int dayFromYear_(int year) {
int flooredDivision(int a, int b) {
return (a - (a < 0 ? b - 1 : 0)) ~/ b;
}
return 365 * (year - 1970)
+ flooredDivision(year - 1969, 4)
- flooredDivision(year - 1901, 100)
+ flooredDivision(year - 1601, 400);
}
// Returns a year in the range 2008-2035 matching
// - leap year, and
// - week day of first day.
// Leap seconds are ignored.
// Adapted from V8's date implementation. See ECMA 262 - 15.9.1.9.
static equivalentYear_(int year) {
// Returns 1 if in leap year. 0 otherwise.
bool inLeapYear(year) {
return (year.remainder(4) == 0) &&
((year.remainder(100) != 0) || (year.remainder(400) == 0));
}
// Returns the week day (in range 0 - 6).
int weekDay(year) {
// 1/1/1970 was a Thursday.
return (dayFromYear_(year) + 4) % 7;
}
// 1/1/1956 was a Sunday (i.e. weekday 0). 1956 was a leap-year.
// 1/1/1967 was a Sunday (i.e. weekday 0).
// Without leap years a subsequent year has a week day + 1 (for example
// 1/1/1968 was a Monday). With leap-years it jumps over one week day
// (e.g. 1/1/1957 was a Tuesday).
// After 12 years the weekdays have advanced by 12 days + 3 leap days =
// 15 days. 15 % 7 = 1. So after 12 years the week day has always
// (now independently of leap-years) advanced by one.
// weekDay * 12 gives thus a year starting with the wanted weekDay.
int recentYear = (inLeapYear(year) ? 1956 : 1967) + (weekDay(year) * 12);
// Close to the year 2008 the calendar cycles every 4 * 7 years (4 for the
// leap years, 7 for the weekdays).
// Find the year in the range 2008..2037 that is equivalent mod 28.
return 2008 + (recentYear - 2008) % 28;
}
static brokenDownDateTimeToMillisecondsSinceEpoch_(
int years, int month, int day,
int hours, int minutes, int seconds, int milliseconds,
bool isUtc) {
if ((month < 1) || (month > 12)) {
throw new IllegalArgumentException();
}
if ((day < 1) || (day > 31)) {
throw new IllegalArgumentException();
}
// Leap seconds can lead to hours == 24.
if ((hours < 0) || (hours > 24)) {
throw new IllegalArgumentException();
}
if ((hours == 24) && ((minutes != 0) || (seconds != 0))) {
throw new IllegalArgumentException();
}
if ((minutes < 0) || (minutes > 59)) {
throw new IllegalArgumentException();
}
if ((seconds < 0) || (seconds > 59)) {
throw new IllegalArgumentException();
}
if ((milliseconds < 0) || (milliseconds > 999)) {
throw new IllegalArgumentException();
}
int equivalentYear;
int offsetInSeconds;
// According to V8 some library calls have troubles with negative values.
// Therefore clamp to 1970 - year 2035 (which is less than the size of
// 32bit).
// We exclude the year 1970 when the time is not UTC, since the epoch
// value could then be negative.
if (years < (isUtc ? 1970 : 1971) || years > 2035) {
equivalentYear = equivalentYear_(years);
int offsetInDays = (dayFromYear_(years) - dayFromYear_(equivalentYear));
// Leap seconds are ignored.
offsetInSeconds = offsetInDays * Time.SECONDS_PER_DAY;
} else {
equivalentYear = years;
offsetInSeconds = 0;
}
int secondsSinceEpoch = brokenDownDateTimeToSecondsSinceEpoch_(
equivalentYear, month, day, hours, minutes, seconds, isUtc);
int adjustedSeconds = secondsSinceEpoch + offsetInSeconds;
return adjustedSeconds * Time.MS_PER_SECOND + milliseconds;
}
// Natives
static brokenDownDateTimeToSecondsSinceEpoch_(
int years, int month, int day, int hours, int minutes, int seconds,
bool isUtc) native "DateTimeNatives_brokenDownToSecondsSinceEpoch";
static int getCurrentMs_() native "DateTimeNatives_currentTimeMillis";
// TODO(floitsch): it would be more efficient if we didn't call the native
// function for every member, but cached the broken-down date.
static int getYear_(int secondsSinceEpoch, bool isUtc)
native "DateTimeNatives_getYear";
static int getMonth_(int secondsSinceEpoch, bool isUtc)
native "DateTimeNatives_getMonth";
static int getDay_(int secondsSinceEpoch, bool isUtc)
native "DateTimeNatives_getDay";
static int getHours_(int secondsSinceEpoch, bool isUtc)
native "DateTimeNatives_getHours";
static int getMinutes_(int secondsSinceEpoch, bool isUtc)
native "DateTimeNatives_getMinutes";
static int getSeconds_(int secondsSinceEpoch, bool isUtc)
native "DateTimeNatives_getSeconds";
}

212
runtime/lib/double.cc Normal file
View file

@ -0,0 +1,212 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include <math.h>
#include "vm/bootstrap_natives.h"
#include "vm/bigint_operations.h"
#include "vm/exceptions.h"
#include "vm/native_entry.h"
#include "vm/object.h"
namespace dart {
DEFINE_NATIVE_ENTRY(Double_doubleFromInteger, 2) {
ASSERT(TypeArguments::CheckedHandle(arguments->At(0)).IsNull());
const Integer& value = Integer::CheckedHandle(arguments->At(1));
const Double& result = Double::Handle(Double::New(value.AsDoubleValue()));
arguments->SetReturn(result);
}
DEFINE_NATIVE_ENTRY(Double_add, 2) {
double left = Double::CheckedHandle(arguments->At(0)).value();
double right = Double::CheckedHandle(arguments->At(1)).value();
const Double& result = Double::Handle(Double::New(left + right));
arguments->SetReturn(result);
}
DEFINE_NATIVE_ENTRY(Double_sub, 2) {
double left = Double::CheckedHandle(arguments->At(0)).value();
double right = Double::CheckedHandle(arguments->At(1)).value();
const Double& result = Double::Handle(Double::New(left - right));
arguments->SetReturn(result);
}
DEFINE_NATIVE_ENTRY(Double_mul, 2) {
double left = Double::CheckedHandle(arguments->At(0)).value();
double right = Double::CheckedHandle(arguments->At(1)).value();
const Double& result = Double::Handle(Double::New(left * right));
arguments->SetReturn(result);
}
DEFINE_NATIVE_ENTRY(Double_div, 2) {
double left = Double::CheckedHandle(arguments->At(0)).value();
double right = Double::CheckedHandle(arguments->At(1)).value();
const Double& result = Double::Handle(Double::New(left / right));
arguments->SetReturn(result);
}
DEFINE_NATIVE_ENTRY(Double_trunc_div, 2) {
double left = Double::CheckedHandle(arguments->At(0)).value();
double right = Double::CheckedHandle(arguments->At(1)).value();
const Double& result = Double::Handle(Double::New(trunc(left / right)));
arguments->SetReturn(result);
}
DEFINE_NATIVE_ENTRY(Double_modulo, 2) {
double left = Double::CheckedHandle(arguments->At(0)).value();
double right = Double::CheckedHandle(arguments->At(1)).value();
double remainder = fmod(left, right);
if (remainder == 0.0) {
// We explicitely switch to the positive 0.0 (just in case it was negative).
remainder = +0.0;
} else if (remainder < 0) {
if (right < 0) {
remainder -= right;
} else {
remainder += right;
}
}
const Double& result = Double::Handle(Double::New(remainder));
arguments->SetReturn(result);
}
DEFINE_NATIVE_ENTRY(Double_remainder, 2) {
double left = Double::CheckedHandle(arguments->At(0)).value();
double right = Double::CheckedHandle(arguments->At(1)).value();
const Double& result = Double::Handle(Double::New(fmod(left, right)));
arguments->SetReturn(result);
}
DEFINE_NATIVE_ENTRY(Double_greaterThan, 2) {
const Double& left = Double::CheckedHandle(arguments->At(0));
const Double& right = Double::CheckedHandle(arguments->At(1));
bool result = right.IsNull() ? false : (left.value() > right.value());
arguments->SetReturn(Bool::Handle(Bool::Get(result)));
}
DEFINE_NATIVE_ENTRY(Double_greaterThanFromInteger, 2) {
const Double& right = Double::CheckedHandle(arguments->At(0));
const Integer& left = Integer::CheckedHandle(arguments->At(1));
const Bool& result = Bool::Handle(Bool::Get(
left.AsDoubleValue() > right.value()));
arguments->SetReturn(result);
}
DEFINE_NATIVE_ENTRY(Double_equal, 2) {
const Double& left = Double::CheckedHandle(arguments->At(0));
const Double& right = Double::CheckedHandle(arguments->At(1));
bool result = right.IsNull() ? false : (left.value() == right.value());
arguments->SetReturn(Bool::Handle(Bool::Get(result)));
}
DEFINE_NATIVE_ENTRY(Double_equalToInteger, 2) {
const Double& left = Double::CheckedHandle(arguments->At(0));
const Integer& right = Integer::CheckedHandle(arguments->At(1));
const Bool& result =
Bool::Handle(Bool::Get(left.value() == right.AsDoubleValue()));
arguments->SetReturn(result);
}
DEFINE_NATIVE_ENTRY(Double_round, 1) {
const Double& arg = Double::CheckedHandle(arguments->At(0));
arguments->SetReturn(Double::Handle(Double::New(round(arg.value()))));
}
DEFINE_NATIVE_ENTRY(Double_floor, 1) {
const Double& arg = Double::CheckedHandle(arguments->At(0));
arguments->SetReturn(Double::Handle(Double::New(floor(arg.value()))));
}
DEFINE_NATIVE_ENTRY(Double_ceil, 1) {
const Double& arg = Double::CheckedHandle(arguments->At(0));
arguments->SetReturn(Double::Handle(Double::New(ceil(arg.value()))));
}
DEFINE_NATIVE_ENTRY(Double_truncate, 1) {
const Double& arg = Double::CheckedHandle(arguments->At(0));
arguments->SetReturn(Double::Handle(Double::New(trunc(arg.value()))));
}
DEFINE_NATIVE_ENTRY(Double_pow, 2) {
const double operand = Double::CheckedHandle(arguments->At(0)).value();
const double exponent = Double::CheckedHandle(arguments->At(1)).value();
arguments->SetReturn(Double::Handle(Double::New(pow(operand, exponent))));
}
#if defined(TARGET_OS_MACOS)
// MAC OSX math library produces old style cast warning.
#pragma GCC diagnostic ignored "-Wold-style-cast"
#endif
DEFINE_NATIVE_ENTRY(Double_toInt, 1) {
const Double& arg = Double::CheckedHandle(arguments->At(0));
if (isinf(arg.value()) || isnan(arg.value())) {
GrowableArray<const Object*> args;
args.Add(&String::ZoneHandle(String::New(
"Infinity or NaN toInt")));
Exceptions::ThrowByType(Exceptions::kBadNumberFormat, args);
}
double result = trunc(arg.value());
if ((Smi::kMinValue <= result) && (result <= Smi::kMaxValue)) {
arguments->SetReturn(Smi::Handle(Smi::New(static_cast<intptr_t>(result))));
} else if ((Mint::kMinValue <= result) && (result <= Mint::kMaxValue)) {
arguments->SetReturn(Mint::Handle(Mint::New(static_cast<int64_t>(result))));
} else {
arguments->SetReturn(
Bigint::Handle(BigintOperations::NewFromDouble(result)));
}
}
DEFINE_NATIVE_ENTRY(Double_isInfinite, 1) {
const Double& arg = Double::CheckedHandle(arguments->At(0));
if (isinf(arg.value())) {
arguments->SetReturn(Bool::Handle(Bool::True()));
} else {
arguments->SetReturn(Bool::Handle(Bool::False()));
}
}
DEFINE_NATIVE_ENTRY(Double_isNaN, 1) {
const Double& arg = Double::CheckedHandle(arguments->At(0));
if (isnan(arg.value())) {
arguments->SetReturn(Bool::Handle(Bool::True()));
} else {
arguments->SetReturn(Bool::Handle(Bool::False()));
}
}
DEFINE_NATIVE_ENTRY(Double_isNegative, 1) {
const Double& arg = Double::CheckedHandle(arguments->At(0));
// Include negative zero, infinity.
if (signbit(arg.value()) && !isnan(arg.value())) {
arguments->SetReturn(Bool::Handle(Bool::True()));
} else {
arguments->SetReturn(Bool::Handle(Bool::False()));
}
}
// Add here only functions using/referring to old-style casts.
} // namespace dart

200
runtime/lib/double.dart Normal file
View file

@ -0,0 +1,200 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
class Double implements double {
factory Double.fromInteger(int value)
native "Double_doubleFromInteger";
int hashCode() {
try {
return toInt();
} catch (BadNumberFormatException e) {
return 0;
}
}
double operator +(num other) {
return add_(other.toDouble());
}
double add_(double other) native "Double_add";
double operator -(num other) {
return sub_(other.toDouble());
}
double sub_(double other) native "Double_sub";
double operator *(num other) {
return mul_(other.toDouble());
}
double mul_(double other) native "Double_mul";
double operator ~/(num other) {
return trunc_div_(other.toDouble());
}
double trunc_div_(double other) native "Double_trunc_div";
double operator /(num other) {
return div_(other.toDouble());
}
double div_(double other) native "Double_div";
double operator %(num other) {
return modulo_(other.toDouble());
}
double modulo_(double other) native "Double_modulo";
double remainder(num other) {
return remainder_(other.toDouble());
}
double remainder_(double other) native "Double_remainder";
double operator negate() {
return 0.0 - this;
}
bool operator ==(other) {
if (!(other is num)) return false;
return equal_(other.toDouble());
}
bool equal_(double other)native "Double_equal";
bool equalToInteger(int other) native "Double_equalToInteger";
bool operator <(num other) {
return other > this;
}
bool operator >(num other) {
return greaterThan_(other.toDouble());
}
bool greaterThan_(double other) native "Double_greaterThan";
bool operator >=(num other) {
return (this == other) || (this > other);
}
bool operator <=(num other) {
return (this == other) || (this < other);
}
double addFromInteger(int other) {
return new Double.fromInteger(other) + this;
}
double subFromInteger(int other) {
return new Double.fromInteger(other) - this;
}
double mulFromInteger(int other) {
return new Double.fromInteger(other) * this;
}
double truncDivFromInteger(int other) {
return new Double.fromInteger(other) ~/ this;
}
double moduloFromInteger(int other) {
return new Double.fromInteger(other) % this;
}
double remainderFromInteger(int other) {
return new Double.fromInteger(other).remainder(this);
}
bool greaterThanFromInteger(int other) native "Double_greaterThanFromInteger";
bool isEven() {
// TODO(floitsch): find more efficient way to implement Double.isEven.
return this % 2.0 == 0.0;
}
bool isOdd() {
// TODO(floitsch): find more efficient way to implement Double.isOdd.
return this % 2.0 == 1.0;
}
bool isNegative() native "Double_isNegative";
bool isInfinite() native "Double_isInfinite";
bool isNaN() native "Double_isNaN";
double abs() {
return this < 0.0 ? -this : this;
}
double round() native "Double_round";
double floor() native "Double_floor";
double ceil () native "Double_ceil";
double truncate() native "Double_truncate";
int toInt() native "Double_toInt";
double toDouble() { return this; }
double pow(num exponent) {
return pow_(exponent.toDouble());
}
double pow_(double exponent) native "Double_pow";
String toStringAsFixed(int fractionDigits) {
// See ECMAScript-262, 15.7.4.5 for details.
// Step 2.
if (fractionDigits < 0 || fractionDigits > 20) {
// TODO(antonm): should be proper RangeError or Dart counterpart.
throw "Range error";
}
// Step 3.
double x = this;
// Step 4.
if (x.isNaN()) {
return "NaN";
}
// Step 5.
String s = "";
// Step 6.
if (x.isNegative()) {
s = "-";
x = -x;
}
// Step 7.
String m;
if (x > 10e21) {
m = x.toString();
} else {
// Step 8.
// Step 8.a.
// This is an approximation for n from the standard.
int n = (x * (10.0).pow(fractionDigits)).round().toInt();
// Step 8.b.
m = n.toString();
// Step 8.c.
if (fractionDigits != 0) {
// Step 8.c.i.
int k = m.length;
// Step 8.c.ii.
if (k <= fractionDigits) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < fractionDigits + 1 - k; i++) {
sb.add("0");
}
String z = sb.toString();
m = z + m;
k = fractionDigits + 1;
}
// Step 8.c.iii.
String a = m.substring(0, k - fractionDigits);
String b = m.substringToEnd(k - fractionDigits);
// Step 8.c.iv.
m = a + "." + b;
}
}
// Step 9.
return s + m;
}
String toStringAsExponential(int fractionDigits) {
throw "Double.toStringAsExponential unimplemented.";
}
String toStringAsPrecision(int precision) {
throw "Double.toStringAsPrecision unimplemented.";
}
String toRadixString(int radix) {
throw "Double.toRadixString unimplemented.";
}
int compareTo(Comparable other) {
if (this == other) return 0;
if (this < other) return -1;
return 1;
}
}

288
runtime/lib/error.cc Normal file
View file

@ -0,0 +1,288 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "lib/error.h"
#include "vm/bootstrap_natives.h"
#include "vm/exceptions.h"
#include "vm/object_store.h"
#include "vm/runtime_entry.h"
#include "vm/stack_frame.h"
namespace dart {
DECLARE_FLAG(bool, print_stack_trace_at_throw);
// Static helpers for allocating, initializing, and throwing an error instance.
// Return the script of the Dart function that called the native entry or the
// runtime entry. The frame iterator points to the callee.
static RawScript* GetCallerScript(DartFrameIterator* iterator) {
DartFrame* caller_frame = iterator->NextFrame();
ASSERT(caller_frame != NULL);
const Function& caller = Function::Handle(caller_frame->LookupDartFunction());
ASSERT(!caller.IsNull());
const Class& caller_class = Class::Handle(caller.owner());
return caller_class.script();
}
// Allocate a new instance of the given class name.
// TODO(hausner): Rename this NewCoreInstance to call out the fact that
// the class name is resolved in the core library implicitly?
static RawInstance* NewInstance(const char* class_name) {
const String& cls_name = String::Handle(String::NewSymbol(class_name));
const Library& core_lib = Library::Handle(Library::CoreLibrary());
Class& cls = Class::Handle(core_lib.LookupClass(cls_name));
ASSERT(!cls.IsNull());
// There are no parameterized error types, so no need to set type arguments.
return Instance::New(cls);
}
// Assign the value to the field given by its name in the given instance.
static void SetField(const Instance& instance,
const Class& cls,
const char* field_name,
const Object& value) {
const Field& field = Field::Handle(cls.LookupInstanceField(
String::Handle(String::NewSymbol(field_name))));
ASSERT(!field.IsNull());
instance.SetField(field, value);
}
// Initialize the fields 'url', 'line', and 'column' in the given instance
// according to the given token location in the given script.
static void SetLocationFields(const Instance& instance,
const Class& cls,
const Script& script,
intptr_t location) {
SetField(instance, cls, "url", String::Handle(script.url()));
intptr_t line, column;
script.GetTokenLocation(location, &line, &column);
SetField(instance, cls, "line", Smi::Handle(Smi::New(line)));
SetField(instance, cls, "column", Smi::Handle(Smi::New(column)));
}
// Allocate and throw a new AssertError.
// Arg0: index of the first token of the failed assertion.
// Arg1: index of the first token after the failed assertion.
// Return value: none, throws an exception.
DEFINE_NATIVE_ENTRY(AssertError_throwNew, 2) {
intptr_t assertion_start = Smi::CheckedHandle(arguments->At(0)).Value();
intptr_t assertion_end = Smi::CheckedHandle(arguments->At(1)).Value();
// Allocate a new instance of type AssertError.
const Instance& assert_error = Instance::Handle(NewInstance("AssertError"));
// Initialize 'url', 'line', and 'column' fields.
DartFrameIterator iterator;
iterator.NextFrame(); // Skip native call.
const Script& script = Script::Handle(GetCallerScript(&iterator));
const Class& cls = Class::Handle(assert_error.clazz());
SetLocationFields(assert_error, cls, script, assertion_start);
// Initialize field 'failed_assertion' with source snippet.
intptr_t from_line, from_column;
script.GetTokenLocation(assertion_start, &from_line, &from_column);
intptr_t to_line, to_column;
script.GetTokenLocation(assertion_end, &to_line, &to_column);
SetField(assert_error, cls, "failedAssertion", String::Handle(
script.GetSnippet(from_line, from_column, to_line, to_column)));
// Throw AssertError instance.
Exceptions::Throw(assert_error);
UNREACHABLE();
}
// Allocate, initialize, and throw a TypeError.
static void ThrowTypeError(intptr_t location,
const String& src_type_name,
const String& dst_type_name,
const String& dst_name) {
// Allocate a new instance of TypeError.
const Instance& type_error = Instance::Handle(NewInstance("TypeError"));
// Initialize 'url', 'line', and 'column' fields.
DartFrameIterator iterator;
const Script& script = Script::Handle(GetCallerScript(&iterator));
const Class& cls = Class::Handle(type_error.clazz());
// Location fields are defined in AssertError, the superclass of TypeError.
const Class& assert_error_class = Class::Handle(cls.SuperClass());
SetLocationFields(type_error, assert_error_class, script, location);
// Initialize field 'failedAssertion' in AssertError superclass.
// Printing the src_obj value would be possible, but ToString() is expensive
// and not meaningful for all classes, so we just print '$expr instanceof...'.
// Users should look at TypeError.ToString(), which contains more useful
// information than AssertError.failedAssertion.
String& failed_assertion = String::Handle(String::New("$expr instanceof "));
failed_assertion = String::Concat(failed_assertion, dst_type_name);
SetField(type_error, assert_error_class, "failedAssertion", failed_assertion);
// Initialize field 'srcType'.
SetField(type_error, cls, "srcType", src_type_name);
// Initialize field 'dstType'.
SetField(type_error, cls, "dstType", dst_type_name);
// Initialize field 'dstName'.
SetField(type_error, cls, "dstName", dst_name);
// Type errors in the core library may be difficult to diagnose.
// Print type error information before throwing the error when debugging.
if (FLAG_print_stack_trace_at_throw) {
OS::Print("Type %s is not assignable to type %s of %s.\n",
src_type_name.ToCString(),
dst_type_name.ToCString(),
dst_name.ToCString());
}
// Throw TypeError instance.
Exceptions::Throw(type_error);
UNREACHABLE();
}
// Allocate and throw a new FallThroughError.
// Arg0: index of the case clause token into which we fall through.
// Return value: none, throws an exception.
DEFINE_NATIVE_ENTRY(FallThroughError_throwNew, 1) {
intptr_t fallthrough_pos = Smi::CheckedHandle(arguments->At(0)).Value();
// Allocate a new instance of type FallThroughError.
const Instance& fallthrough_error =
Instance::Handle(NewInstance("FallThroughError"));
ASSERT(!fallthrough_error.IsNull());
// Initialize 'url' and 'line' fields.
DartFrameIterator iterator;
iterator.NextFrame(); // Skip native call.
const Script& script = Script::Handle(GetCallerScript(&iterator));
const Class& cls = Class::Handle(fallthrough_error.clazz());
SetField(fallthrough_error, cls, "url", String::Handle(script.url()));
intptr_t line, column;
script.GetTokenLocation(fallthrough_pos, &line, &column);
SetField(fallthrough_error, cls, "line", Smi::Handle(Smi::New(line)));
// Throw FallThroughError instance.
Exceptions::Throw(fallthrough_error);
UNREACHABLE();
}
// Check that the type of the given instance is assignable to the given type.
// Arg0: index of the token of the assignment (source location).
// Arg1: instance being assigned.
// Arg2: type being assigned to.
// Arg3: type arguments of the instantiator of the type being assigned to.
// Arg4: name of instance being assigned to.
// Return value: instance if assignable, otherwise throw a TypeError.
DEFINE_RUNTIME_ENTRY(TypeCheck, 5) {
ASSERT(arguments.Count() == kTypeCheckRuntimeEntry.argument_count());
intptr_t location = Smi::CheckedHandle(arguments.At(0)).Value();
const Instance& src_instance = Instance::CheckedHandle(arguments.At(1));
const Type& dst_type = Type::CheckedHandle(arguments.At(2));
const TypeArguments& dst_type_instantiator =
TypeArguments::CheckedHandle(arguments.At(3));
const String& dst_name = String::CheckedHandle(arguments.At(4));
ASSERT(!dst_type.IsVarType()); // No need to check assignment to 'var type'.
ASSERT(!src_instance.IsNull()); // Already checked in inlined code.
if (!src_instance.IsAssignableTo(dst_type, dst_type_instantiator)) {
const Type& src_type = Type::Handle(src_instance.GetType());
const String& src_type_name = String::Handle(src_type.Name());
String& dst_type_name = String::Handle();
if (!dst_type.IsInstantiated()) {
// Instantiate dst_type before reporting the error.
const Type& instantiated_dst_type = Type::Handle(
dst_type.InstantiateFrom(dst_type_instantiator, 0));
dst_type_name = instantiated_dst_type.Name();
} else {
dst_type_name = dst_type.Name();
}
ThrowTypeError(location, src_type_name, dst_type_name, dst_name);
UNREACHABLE();
}
arguments.SetReturn(src_instance);
}
// Check that the type of the given object is allowed in conditional context.
// Arg0: index of the token of the assignment (source location).
// Arg1: object being checked.
// Return value: checked value, otherwise allocate and throw a TypeError.
DEFINE_RUNTIME_ENTRY(ConditionTypeCheck, 2) {
ASSERT(arguments.Count() ==
kConditionTypeCheckRuntimeEntry.argument_count());
intptr_t location = Smi::CheckedHandle(arguments.At(0)).Value();
const Instance& src_instance = Instance::CheckedHandle(arguments.At(1));
const char* msg = "boolean expression";
if (src_instance.IsNull() || !src_instance.IsBool()) {
const Type& bool_interface =
Type::ZoneHandle(Isolate::Current()->object_store()->bool_interface());
const Type& src_type = Type::Handle(src_instance.GetType());
const String& src_type_name = String::Handle(src_type.Name());
const String& bool_type_name = String::Handle(bool_interface.Name());
ThrowTypeError(location, src_type_name, bool_type_name,
String::Handle(String::NewSymbol(msg)));
UNREACHABLE();
}
arguments.SetReturn(src_instance);
}
// Check that the type of each element of the given array is assignable to the
// given type.
// Arg0: index of the token of the rest argument declaration (source location).
// Arg1: rest argument array.
// Arg2: element declaration type.
// Arg3: type arguments of the instantiator of the element declaration type.
// Arg4: name of object being assigned to, i.e. name of rest argument.
// Return value: null if assignable, otherwise allocate and throw a TypeError.
DEFINE_RUNTIME_ENTRY(RestArgumentTypeCheck, 5) {
ASSERT(arguments.Count() ==
kRestArgumentTypeCheckRuntimeEntry.argument_count());
intptr_t location = Smi::CheckedHandle(arguments.At(0)).Value();
const Array& rest_array = Array::CheckedHandle(arguments.At(1));
const Type& element_type = Type::CheckedHandle(arguments.At(2));
const TypeArguments& element_type_instantiator =
TypeArguments::CheckedHandle(arguments.At(3));
const String& rest_name = String::CheckedHandle(arguments.At(4));
ASSERT(!element_type.IsVarType()); // No need to check assignment.
ASSERT(!rest_array.IsNull());
Instance& elem = Instance::Handle();
for (intptr_t i = 0; i < rest_array.Length(); i++) {
elem ^= rest_array.At(i);
if (!elem.IsNull() &&
!elem.IsAssignableTo(element_type, element_type_instantiator)) {
// Allocate and throw a new instance of TypeError.
char buf[256];
OS::SNPrint(buf, sizeof(buf), "%s[%d]",
rest_name.ToCString(), static_cast<int>(i));
const String& src_type_name =
String::Handle(Type::Handle(elem.GetType()).Name());
String& dst_type_name = String::Handle();
if (!element_type.IsInstantiated()) {
// Instantiate element_type before reporting the error.
const Type& instantiated_element_type = Type::Handle(
element_type.InstantiateFrom(element_type_instantiator, 0));
dst_type_name = instantiated_element_type.Name();
} else {
dst_type_name = element_type.Name();
}
const String& dst_name = String::Handle(String::New(buf));
ThrowTypeError(location, src_type_name, dst_type_name, dst_name);
UNREACHABLE();
}
}
}
} // namespace dart

55
runtime/lib/error.dart Normal file
View file

@ -0,0 +1,55 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Errors are created and thrown by DartVM only.
class AssertError {
factory AssertError._uninstantiable() {
throw const UnsupportedOperationException(
"AssertError can only be allocated by the VM");
}
static throwNew(int assertionStart, int assertionEnd)
native "AssertError_throwNew";
String toString() {
return "Failed assertion: '$failedAssertion' is not true " +
"in $url at line $line, column $column.";
}
final String failedAssertion;
final String url;
final int line;
final int column;
}
class TypeError extends AssertError {
factory TypeError._uninstantiable() {
throw const UnsupportedOperationException(
"TypeError can only be allocated by the VM");
}
String toString() {
return "Failed type check: type $srcType is not assignable to type " +
"$dstType of $dstName in $url at line " +
"$line, column $column.";
}
final String srcType;
final String dstType;
final String dstName;
}
class FallThroughError {
factory FallThroughError._uninstantiable() {
throw const UnsupportedOperationException(
"FallThroughError can only be allocated by the VM");
}
static throwNew(int case_clause_pos) native "FallThroughError_throwNew";
String toString() {
return "Switch case fall-through in $url at line $line.";
}
final String url;
final int line;
}
class InternalError {
const InternalError(this._msg);
String toString() => "InternalError: '${_msg}'";
final String _msg;
}

19
runtime/lib/error.h Normal file
View file

@ -0,0 +1,19 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef LIB_ERROR_H_
#define LIB_ERROR_H_
#include "vm/runtime_entry.h"
namespace dart {
DECLARE_RUNTIME_ENTRY(ConditionTypeCheck);
DECLARE_RUNTIME_ENTRY(RestArgumentTypeCheck);
DECLARE_RUNTIME_ENTRY(TypeCheck);
} // namespace dart
#endif // LIB_ERROR_H_

View file

@ -0,0 +1,182 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
class GrowableObjectArray<T> implements Array<T> {
Array<T> backingArray;
void copyFrom(Array<Object> src, int srcStart, int dstStart, int count) {
Arrays.copy(src, srcStart, this, dstStart, count);
}
// The length of this growable array. It is always less than the
// length of the backing array.
int _length;
// Constant used by indexOf and lastIndexOf when the element given
// is not in the array.
static final int ABSENT = -1;
GrowableObjectArray()
: _length = 0, backingArray = new ObjectArray<T>(4) {}
GrowableObjectArray.withCapacity(int capacity) {
_length = 0;
if (capacity <= 0) {
capacity = 4;
}
backingArray = new ObjectArray<T>(capacity);
}
GrowableObjectArray._usingArray(Array<T> array) {
backingArray = array;
_length = array.length;
if (_length == 0) {
grow(4);
}
}
factory GrowableObjectArray.from(Collection<T> other) {
Array result = new GrowableObjectArray();
result.addAll(other);
return result;
}
int get length() {
return _length;
}
void set length(int new_length) {
if (new_length >= backingArray.length) {
grow(new_length);
} else {
for (int i = new_length; i < _length; i++) {
backingArray[i] = null;
}
}
_length = new_length;
}
T operator [](int index) {
if (index >= _length) {
throw new IndexOutOfRangeException(index);
}
return backingArray[index];
}
void operator []=(int index, T value) {
if (index >= _length) {
throw new IndexOutOfRangeException(index);
}
backingArray[index] = value;
}
void grow(int capacity) {
Array<T> newArray = new ObjectArray<T>(capacity);
int length = backingArray.length;
for (int i = 0; i < length; i++) {
newArray[i] = backingArray[i];
}
backingArray = newArray;
}
int add(T value) {
if (_length == backingArray.length) {
grow(_length * 2);
}
backingArray[_length] = value;
return ++_length;
}
void addLast(T element) {
add(element);
}
void addAll(Collection<T> collection) {
for (T elem in collection) {
add(elem);
}
}
T removeLast() {
_length--;
return backingArray[_length];
}
T last() {
if (_length === 0) {
throw new IndexOutOfRangeException(-1);
}
return backingArray[_length - 1];
}
int indexOf(T element, int startIndex) {
return Arrays.indexOf(backingArray, element, startIndex, _length);
}
int lastIndexOf(T element, int startIndex) {
return Arrays.lastIndexOf(backingArray, element, startIndex);
}
/**
* Collection interface.
*/
void forEach(f(T element)) {
// TODO(srdjan): Use Collections.forEach(this, f);
// Using backingArray directly improves DeltaBlue performance by 25%.
for (int i = 0; i < _length; i++) {
f(backingArray[i]);
}
}
Collection<T> filter(bool f(T element)) {
return Collections.filter(this, new GrowableObjectArray<T>(), f);
}
bool every(bool f(T element)) {
return Collections.every(this, f);
}
bool some(bool f(T element)) {
return Collections.some(this, f);
}
bool isEmpty() {
return this.length === 0;
}
void clear() {
this.length = 0;
}
void sort(int compare(T a, T b)) {
DualPivotQuicksort.sort(this, compare);
}
Iterator<T> iterator() {
return new VariableSizeArrayIterator<T>(this);
}
}
// Iterator for arrays with variable size.
class VariableSizeArrayIterator<T> implements Iterator<T> {
VariableSizeArrayIterator(GrowableObjectArray<T> array)
: _array = array, _pos = 0 {
}
bool hasNext() {
return _array._length > _pos;
}
T next() {
if (!hasNext()) {
throw const NoMoreElementsException();
}
return _array[_pos++];
}
final GrowableObjectArray<T> _array;
int _pos;
}

View file

@ -0,0 +1,108 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Immutable map class for compiler generated map literals.
class ImmutableMap<K, V> implements Map<K, V> {
final ImmutableArray kvPairs_;
const ImmutableMap(ImmutableArray keyValuePairs)
: kvPairs_ = keyValuePairs;
V operator [](K key) {
// TODO(hausner): Since the keys are sorted, we could do a binary
// search. But is it worth it?
for (int i = 0; i < kvPairs_.length - 1; i += 2) {
if (key == kvPairs_[i]) {
return kvPairs_[i+1];
}
}
return null;
}
bool isEmpty() {
return kvPairs_.length === 0;
}
int get length() {
return kvPairs_.length ~/ 2;
}
void forEach(void f(K key, V value)) {
for (int i = 0; i < kvPairs_.length; i += 2) {
f(kvPairs_[i], kvPairs_[i+1]);
}
}
Collection<K> getKeys() {
int numKeys = length;
Array<K> array = new Array<K>(numKeys);
for (int i = 0; i < numKeys; i++) {
array[i] = kvPairs_[i*2];
}
return array;
}
Collection<V> getValues() {
int numValues = length;
Array<K> array = new Array<K>(numValues);
for (int i = 0; i < numValues; i++) {
array[i] = kvPairs_[i*2 + 1];
}
return array;
}
bool containsKey(K key) {
for (int i = 0; i < kvPairs_.length; i += 2) {
if (key == kvPairs_[i]) {
return true;
}
}
return false;
}
bool containsValue(V value) {
for (int i = 1; i < kvPairs_.length; i += 2) {
if (value == kvPairs_[i]) {
return true;
}
}
return false;
}
void operator []=(K key, V value) {
throw const IllegalAccessException();
}
V putIfAbsent(K key, V ifAbsent()) {
throw const IllegalAccessException();
}
void clear() {
throw const IllegalAccessException();
}
V remove(K key) {
throw const IllegalAccessException();
}
String toString() {
// TODO(srdjan): Extend text representation.
return "ImmutableMap";
}
}
class MutableMap {
// [elements] contains n key-value pairs. The keys are at position
// 2*n, the values at position 2*n+1.
static fromLiteral(Array elements) {
var map = new LinkedHashMap();
var len = elements.length;
for (int i = 1; i < len; i += 2) {
map[elements[i-1]] = elements[i];
}
return map;
}
}

586
runtime/lib/integers.cc Normal file
View file

@ -0,0 +1,586 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/bootstrap_natives.h"
#include "vm/bigint_operations.h"
#include "vm/dart_entry.h"
#include "vm/native_entry.h"
#include "vm/object.h"
namespace dart {
DEFINE_FLAG(bool, trace_intrinsified_natives, false,
"Report if any of the intrinsified natives are called");
// Smi natives.
// Return the most compact presentation of an integer.
static RawInteger* AsInteger(const Integer& value) {
if (value.IsSmi()) return value.raw();
if (value.IsMint()) {
Mint& mint = Mint::Handle();
mint ^= value.raw();
if (Smi::IsValid64(mint.value())) {
return Smi::New(mint.value());
} else {
return value.raw();
}
}
ASSERT(value.IsBigint());
Bigint& big_value = Bigint::Handle();
big_value ^= value.raw();
if (BigintOperations::FitsIntoSmi(big_value)) {
return BigintOperations::ToSmi(big_value);
} else if (BigintOperations::FitsIntoInt64(big_value)) {
return Mint::New(BigintOperations::ToInt64(big_value));
} else {
return big_value.raw();
}
}
// Returns value in form of a RawBigint.
static RawBigint* AsBigint(const Integer& value) {
ASSERT(!value.IsNull());
if (value.IsSmi()) {
Smi& smi = Smi::Handle();
smi ^= value.raw();
return BigintOperations::NewFromSmi(smi);
} else if (value.IsMint()) {
Mint& mint = Mint::Handle();
mint ^= value.raw();
return BigintOperations::NewFromInt64(mint.value());
} else {
ASSERT(value.IsBigint());
Bigint& big = Bigint::Handle();
big ^= value.raw();
ASSERT(!BigintOperations::FitsIntoSmi(big));
return big.raw();
}
}
static bool Are64bitOperands(const Integer& op1, const Integer& op2) {
return !op1.IsBigint() && !op2.IsBigint();
}
static RawInteger* IntegerBitOperation(Token::Kind kind,
const Integer& op1_int,
const Integer& op2_int) {
if (op1_int.IsSmi() && op2_int.IsSmi()) {
Smi& op1 = Smi::Handle();
Smi& op2 = Smi::Handle();
op1 ^= op1_int.raw();
op2 ^= op2_int.raw();
intptr_t result = 0;
switch (kind) {
case Token::kBIT_AND:
result = op1.Value() & op2.Value();
break;
case Token::kBIT_OR:
result = op1.Value() | op2.Value();
break;
case Token::kBIT_XOR:
result = op1.Value() ^ op2.Value();
break;
default:
UNIMPLEMENTED();
}
ASSERT(Smi::IsValid(result));
return Smi::New(result);
} else if (Are64bitOperands(op1_int, op2_int)) {
int64_t a = op1_int.AsInt64Value();
int64_t b = op2_int.AsInt64Value();
switch (kind) {
case Token::kBIT_AND:
return Integer::New(a & b);
case Token::kBIT_OR:
return Integer::New(a | b);
case Token::kBIT_XOR:
return Integer::New(a ^ b);
default:
UNIMPLEMENTED();
}
} else if (op1_int.IsSmi()) {
return IntegerBitOperation(kind, op2_int, op1_int);
} else if (op2_int.IsSmi()) {
Bigint& op1 = Bigint::Handle(AsBigint(op1_int));
Smi& op2 = Smi::Handle();
op2 ^= op2_int.raw();
switch (kind) {
case Token::kBIT_AND:
return BigintOperations::BitAndWithSmi(op1, op2);
case Token::kBIT_OR:
return BigintOperations::BitOrWithSmi(op1, op2);
case Token::kBIT_XOR:
return BigintOperations::BitXorWithSmi(op1, op2);
default:
UNIMPLEMENTED();
}
} else {
Bigint& op1 = Bigint::Handle(AsBigint(op1_int));
Bigint& op2 = Bigint::Handle(AsBigint(op2_int));
switch (kind) {
case Token::kBIT_AND:
return BigintOperations::BitAnd(op1, op2);
case Token::kBIT_OR:
return BigintOperations::BitOr(op1, op2);
case Token::kBIT_XOR:
return BigintOperations::BitXor(op1, op2);
default:
UNIMPLEMENTED();
}
}
return Integer::null();
}
// Returns false if integer is in wrong representation, e.g., as is a Bigint
// when it could have been a Smi.
static bool CheckInteger(const Integer& i) {
if (i.IsBigint()) {
Bigint& bigint = Bigint::Handle();
bigint ^= i.raw();
return !BigintOperations::FitsIntoSmi(bigint) &&
!BigintOperations::FitsIntoInt64(bigint);
}
if (i.IsMint()) {
Mint& mint = Mint::Handle();
mint ^= i.raw();
return !Smi::IsValid64(mint.value());
}
return true;
}
DEFINE_NATIVE_ENTRY(Integer_bitAndFromInteger, 2) {
const Integer& right = Integer::CheckedHandle(arguments->At(0));
const Integer& left = Integer::CheckedHandle(arguments->At(1));
ASSERT(CheckInteger(right));
ASSERT(CheckInteger(left));
if (FLAG_trace_intrinsified_natives) {
OS::Print("Integer_bitAndFromInteger %s & %s\n",
right.ToCString(), left.ToCString());
}
Integer& result = Integer::Handle(
IntegerBitOperation(Token::kBIT_AND, left, right));
arguments->SetReturn(Integer::Handle(AsInteger(result)));
}
DEFINE_NATIVE_ENTRY(Integer_bitOrFromInteger, 2) {
const Integer& right = Integer::CheckedHandle(arguments->At(0));
const Integer& left = Integer::CheckedHandle(arguments->At(1));
ASSERT(CheckInteger(right));
ASSERT(CheckInteger(left));
if (FLAG_trace_intrinsified_natives) {
OS::Print("Integer_bitOrFromInteger %s | %s\n",
left.ToCString(), right.ToCString());
}
Integer& result = Integer::Handle(
IntegerBitOperation(Token::kBIT_OR, left, right));
arguments->SetReturn(Integer::Handle(AsInteger(result)));
}
DEFINE_NATIVE_ENTRY(Integer_bitXorFromInteger, 2) {
const Integer& right = Integer::CheckedHandle(arguments->At(0));
const Integer& left = Integer::CheckedHandle(arguments->At(1));
ASSERT(CheckInteger(right));
ASSERT(CheckInteger(left));
if (FLAG_trace_intrinsified_natives) {
OS::Print("Integer_bitXorFromInteger %s ^ %s\n",
left.ToCString(), right.ToCString());
}
Integer& result = Integer::Handle(
IntegerBitOperation(Token::kBIT_XOR, left, right));
arguments->SetReturn(Integer::Handle(AsInteger(result)));
}
// The result is invalid if it is outside the range
// Smi::kMaxValue..Smi::kMinValue.
static int64_t BinaryOpWithTwoSmis(Token::Kind operation,
const Smi& left,
const Smi& right) {
switch (operation) {
case Token::kADD:
return left.Value() + right.Value();
case Token::kSUB:
return left.Value() - right.Value();
case Token::kMUL: {
#if defined(TARGET_ARCH_X64)
// Overflow check for 64-bit platforms unimplemented.
UNIMPLEMENTED();
return 0;
#else
int64_t result_64 =
static_cast<int64_t>(left.Value()) *
static_cast<int64_t>(right.Value());
return result_64;
#endif
}
case Token::kTRUNCDIV:
return left.Value() / right.Value();
case Token::kMOD: {
intptr_t remainder = left.Value() % right.Value();
if (remainder < 0) {
if (right.Value() < 0) {
return remainder - right.Value();
} else {
return remainder + right.Value();
}
} else {
return remainder;
}
}
default:
UNIMPLEMENTED();
return 0;
}
}
static RawBigint* BinaryOpWithTwoBigints(Token::Kind operation,
const Bigint& left,
const Bigint& right) {
switch (operation) {
case Token::kADD:
return BigintOperations::Add(left, right);
case Token::kSUB:
return BigintOperations::Subtract(left, right);
case Token::kMUL:
return BigintOperations::Multiply(left, right);
case Token::kTRUNCDIV:
return BigintOperations::Divide(left, right);
case Token::kMOD:
return BigintOperations::Modulo(left, right);
default:
UNIMPLEMENTED();
return Bigint::null();
}
}
// TODO(srdjan): Implement correct overflow checking before allowing 64 bit
// operands.
static bool AreBoth64bitOperands(const Integer& op1, const Integer& op2) {
return false;
}
static RawInteger* IntegerBinopHelper(Token::Kind operation,
const Integer& left_int,
const Integer& right_int) {
if (left_int.IsSmi() && right_int.IsSmi()) {
Smi& left_smi = Smi::Handle();
Smi& right_smi = Smi::Handle();
left_smi ^= left_int.raw();
right_smi ^= right_int.raw();
int64_t result = BinaryOpWithTwoSmis(operation, left_smi, right_smi);
if (Smi::IsValid64(result)) {
return Smi::New(result);
} else {
// Overflow to Mint.
return Mint::New(result);
}
} else if (AreBoth64bitOperands(left_int, right_int)) {
// TODO(srdjan): Test for overflow of result instead of operand
// types.
const int64_t a = left_int.AsInt64Value();
const int64_t b = right_int.AsInt64Value();
switch (operation) {
case Token::kADD:
return Integer::New(a + b);
case Token::kSUB:
return Integer::New(a - b);
case Token::kMUL:
return Integer::New(a * b);
case Token::kTRUNCDIV:
return Integer::New(a / b);
case Token::kMOD: {
int64_t remainder = a % b;
int64_t c = 0;
if (remainder < 0) {
if (b < 0) {
c = remainder - b;
} else {
c = remainder + b;
}
} else {
c = remainder;
}
return Integer::New(c);
}
default:
UNIMPLEMENTED();
}
}
const Bigint& left_big = Bigint::Handle(AsBigint(left_int));
const Bigint& right_big = Bigint::Handle(AsBigint(right_int));
const Bigint& result =
Bigint::Handle(BinaryOpWithTwoBigints(operation, left_big, right_big));
return Integer::Handle(AsInteger(result)).raw();
}
DEFINE_NATIVE_ENTRY(Integer_addFromInteger, 2) {
const Integer& right_int = Integer::CheckedHandle(arguments->At(0));
const Integer& left_int = Integer::CheckedHandle(arguments->At(1));
ASSERT(CheckInteger(right_int));
ASSERT(CheckInteger(left_int));
if (FLAG_trace_intrinsified_natives) {
OS::Print("Integer_addFromInteger %s + %s\n",
left_int.ToCString(), right_int.ToCString());
}
const Integer& result =
Integer::Handle(IntegerBinopHelper(Token::kADD, left_int, right_int));
arguments->SetReturn(result);
}
DEFINE_NATIVE_ENTRY(Integer_subFromInteger, 2) {
const Integer& right_int = Integer::CheckedHandle(arguments->At(0));
const Integer& left_int = Integer::CheckedHandle(arguments->At(1));
ASSERT(CheckInteger(right_int));
ASSERT(CheckInteger(left_int));
if (FLAG_trace_intrinsified_natives) {
OS::Print("Integer_subFromInteger %s - %s\n",
left_int.ToCString(), right_int.ToCString());
}
const Integer& result =
Integer::Handle(IntegerBinopHelper(Token::kSUB, left_int, right_int));
arguments->SetReturn(result);
}
DEFINE_NATIVE_ENTRY(Integer_mulFromInteger, 2) {
const Integer& right_int = Integer::CheckedHandle(arguments->At(0));
const Integer& left_int = Integer::CheckedHandle(arguments->At(1));
ASSERT(CheckInteger(right_int));
ASSERT(CheckInteger(left_int));
if (FLAG_trace_intrinsified_natives) {
OS::Print("Integer_mulFromInteger %s * %s\n",
left_int.ToCString(), right_int.ToCString());
}
const Integer& result =
Integer::Handle(IntegerBinopHelper(Token::kMUL, left_int, right_int));
arguments->SetReturn(result);
}
DEFINE_NATIVE_ENTRY(Integer_truncDivFromInteger, 2) {
const Integer& right_int = Integer::CheckedHandle(arguments->At(0));
const Integer& left_int = Integer::CheckedHandle(arguments->At(1));
ASSERT(CheckInteger(right_int));
ASSERT(CheckInteger(left_int));
ASSERT(!right_int.IsZero());
const Integer& result = Integer::Handle(
IntegerBinopHelper(Token::kTRUNCDIV, left_int, right_int));
arguments->SetReturn(result);
}
DEFINE_NATIVE_ENTRY(Integer_moduloFromInteger, 2) {
const Integer& right_int = Integer::CheckedHandle(arguments->At(0));
const Integer& left_int = Integer::CheckedHandle(arguments->At(1));
ASSERT(CheckInteger(right_int));
ASSERT(CheckInteger(right_int));
if (FLAG_trace_intrinsified_natives) {
OS::Print("Integer_moduloFromInteger %s mod %s\n",
left_int.ToCString(), right_int.ToCString());
}
if (right_int.IsZero()) {
// Should have been caught before calling into runtime.
UNIMPLEMENTED();
}
const Integer& result =
Integer::Handle(IntegerBinopHelper(Token::kMOD, left_int, right_int));
arguments->SetReturn(result);
}
DEFINE_NATIVE_ENTRY(Integer_greaterThanFromInteger, 2) {
const Integer& right = Integer::CheckedHandle(arguments->At(0));
const Integer& left = Integer::CheckedHandle(arguments->At(1));
ASSERT(CheckInteger(right));
ASSERT(CheckInteger(left));
if (FLAG_trace_intrinsified_natives) {
OS::Print("Integer_greaterThanFromInteger %s > %s\n",
left.ToCString(), right.ToCString());
}
const Bool& result = Bool::Handle(Bool::Get(left.CompareWith(right) == 1));
arguments->SetReturn(result);
}
DEFINE_NATIVE_ENTRY(Integer_equalToInteger, 2) {
const Integer& left = Integer::CheckedHandle(arguments->At(0));
const Integer& right = Integer::CheckedHandle(arguments->At(1));
ASSERT(CheckInteger(left));
ASSERT(CheckInteger(right));
if (FLAG_trace_intrinsified_natives) {
OS::Print("Integer_equalToInteger %s == %s\n",
left.ToCString(), right.ToCString());
}
const Bool& result = Bool::Handle(Bool::Get(left.CompareWith(right) == 0));
arguments->SetReturn(result);
}
static int HighestBit(int64_t v) {
uint64_t t = static_cast<uint64_t>((v > 0) ? v : -v);
int count = 0;
while ((t >>= 1) != 0) {
count++;
}
return count;
}
// TODO(srdjan): Clarify handling of negative right operand in a shift op.
static RawInteger* SmiShiftOperation(Token::Kind kind,
const Smi& left,
const Smi& right) {
ASSERT(right.Value() >= 0);
intptr_t result = 0;
switch (kind) {
case Token::kSHL:
if ((left.Value() == 0) || (right.Value() == 0)) {
return left.raw();
}
{ // Check for overflow.
int cnt = HighestBit(left.Value());
if ((cnt + right.Value()) >= Smi::kBits) {
if ((cnt + right.Value()) >= Mint::kBits) {
return BigintOperations::ShiftLeft(
Bigint::Handle(AsBigint(left)), right.Value());
} else {
int64_t left_64 = left.Value();
return Integer::New(left_64 << right.Value());
}
}
}
result = left.Value() << right.Value();
break;
case Token::kSAR: {
int shift_amount = (right.Value() > 0x1F) ? 0x1F : right.Value();
result = left.Value() >> shift_amount;
break;
}
default:
UNIMPLEMENTED();
}
ASSERT(Smi::IsValid(result));
return Smi::New(result);
}
static RawInteger* ShiftOperationHelper(Token::Kind kind,
const Integer& value,
const Smi& amount) {
if (amount.Value() < 0) {
// TODO(srdjan): Throw exception maybe.
UNIMPLEMENTED();
}
if (value.IsSmi()) {
Smi& smi_value = Smi::Handle();
smi_value ^= value.raw();
return SmiShiftOperation(kind, smi_value, amount);
}
Bigint& big_value = Bigint::Handle();
if (value.IsMint()) {
const int64_t mint_value = value.AsInt64Value();
const int count = HighestBit(mint_value);
if ((count + amount.Value()) < Mint::kBits) {
switch (kind) {
case Token::kSHL:
return Integer::New(mint_value << amount.Value());
case Token::kSAR:
return Integer::New(mint_value >> amount.Value());
default:
UNIMPLEMENTED();
}
} else {
// Overflow in shift, use Bigints
big_value = BigintOperations::NewFromInt64(mint_value);
}
} else {
ASSERT(value.IsBigint());
big_value ^= value.raw();
}
switch (kind) {
case Token::kSHL:
return BigintOperations::ShiftLeft(big_value, amount.Value());
case Token::kSAR:
return BigintOperations::ShiftRight(big_value, amount.Value());
default:
UNIMPLEMENTED();
}
return Integer::null();
}
DEFINE_NATIVE_ENTRY(Smi_sarFromInt, 2) {
const Smi& amount = Smi::CheckedHandle(arguments->At(0));
const Integer& value = Integer::CheckedHandle(arguments->At(1));
ASSERT(CheckInteger(amount));
ASSERT(CheckInteger(value));
Integer& result = Integer::Handle(
ShiftOperationHelper(Token::kSAR, value, amount));
arguments->SetReturn(Integer::Handle(AsInteger(result)));
}
DEFINE_NATIVE_ENTRY(Smi_shlFromInt, 2) {
const Smi& amount = Smi::CheckedHandle(arguments->At(0));
const Integer& value = Integer::CheckedHandle(arguments->At(1));
ASSERT(CheckInteger(amount));
ASSERT(CheckInteger(value));
if (FLAG_trace_intrinsified_natives) {
OS::Print("Smi_shlFromInt: %s << %s\n",
value.ToCString(), amount.ToCString());
}
Integer& result = Integer::Handle(
ShiftOperationHelper(Token::kSHL, value, amount));
arguments->SetReturn(Integer::Handle(AsInteger(result)));
}
DEFINE_NATIVE_ENTRY(Smi_bitNegate, 1) {
const Smi& operand = Smi::CheckedHandle(arguments->At(0));
if (FLAG_trace_intrinsified_natives) {
OS::Print("Smi_bitNegate: %s\n", operand.ToCString());
}
intptr_t result = ~operand.Value();
ASSERT(Smi::IsValid(result));
arguments->SetReturn(Smi::Handle(Smi::New(result)));
}
// Mint natives.
DEFINE_NATIVE_ENTRY(Mint_bitNegate, 1) {
const Mint& operand = Mint::CheckedHandle(arguments->At(0));
ASSERT(CheckInteger(operand));
if (FLAG_trace_intrinsified_natives) {
OS::Print("Mint_bitNegate: %s\n", operand.ToCString());
}
int64_t result = ~operand.value();
arguments->SetReturn(Integer::Handle(Integer::New(result)));
}
// Bigint natives.
DEFINE_NATIVE_ENTRY(Bigint_bitNegate, 1) {
const Bigint& value = Bigint::CheckedHandle(arguments->At(0));
const Bigint& result = Bigint::Handle(BigintOperations::BitNot(value));
ASSERT(CheckInteger(value));
ASSERT(CheckInteger(result));
arguments->SetReturn(Integer::Handle(AsInteger(result)));
}
} // namespace dart

182
runtime/lib/integers.dart Normal file
View file

@ -0,0 +1,182 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// TODO(srdjan): fix limitations.
// - shift amount must be a Smi.
class IntegerImplementation {
num operator +(num other) {
return other.addFromInteger(this);
}
num operator -(num other) {
return other.subFromInteger(this);
}
num operator *(num other) {
return other.mulFromInteger(this);
}
num operator ~/(num other) {
if (other == 0) {
throw const IntegerDivisionByZeroException();
}
return other.truncDivFromInteger(this);
}
num operator /(num other) {
return this.toDouble() / other.toDouble();
}
num operator %(num other) {
if (other == 0) {
throw const IntegerDivisionByZeroException();
}
return other.moduloFromInteger(this);
}
int operator negate() {
return 0 - this;
}
int operator &(int other) {
return other.bitAndFromInteger(this);
}
int operator |(int other) {
return other.bitOrFromInteger(this);
}
int operator ^(int other) {
return other.bitXorFromInteger(this);
}
num remainder(num other) {
return other.remainderFromInteger(this);
}
int bitAndFromInteger(int other) native "Integer_bitAndFromInteger";
int bitOrFromInteger(int other) native "Integer_bitOrFromInteger";
int bitXorFromInteger(int other) native "Integer_bitXorFromInteger";
int addFromInteger(int other) native "Integer_addFromInteger";
int subFromInteger(int other) native "Integer_subFromInteger";
int mulFromInteger(int other) native "Integer_mulFromInteger";
int truncDivFromInteger(int other) native "Integer_truncDivFromInteger";
int moduloFromInteger(int other) native "Integer_moduloFromInteger";
int remainderFromInteger(int other) {
return other - (other ~/ this) * this;
}
int operator >>(int other) {
return other.sarFromInt(this);
}
int operator <<(int other) {
return other.shlFromInt(this);
}
bool operator <(num other) {
return other > this;
}
bool operator >(num other) {
return other.greaterThanFromInteger(this);
}
bool operator >=(num other) {
return (this == other) || (this > other);
}
bool operator <=(num other) {
return (this == other) || (this < other);
}
bool greaterThanFromInteger(int other)
native "Integer_greaterThanFromInteger";
bool operator ==(other) {
if (other is num) {
return other.equalToInteger(this);
}
return false;
}
bool equalToInteger(int other) native "Integer_equalToInteger";
int abs() {
return this < 0 ? -this : this;
}
bool isEven() { return ((this & 1) === 0); }
bool isOdd() { return !isEven(); }
bool isNaN() { return false; }
bool isNegative() { return this < 0; }
bool isInfinite() { return false; }
int compareTo(Comparable other) {
if (this == other) return 0;
if (this < other) return -1;
return 1;
}
int round() { return this; }
int floor() { return this; }
int ceil() { return this; }
int truncate() { return this; }
int toInt() { return this; }
double toDouble() { return new Double.fromInteger(this); }
int pow(int exponent) {
throw "IntegerImplementation.pow not implemented";
}
String toStringAsFixed(int fractionDigits) {
throw "IntegerImplementation.toStringAsFixed not implemented";
}
String toStringAsExponential(int fractionDigits) {
throw "IntegerImplementation.toStringAsExponential not implemented";
}
String toStringAsPrecision(int precision) {
throw "IntegerImplementation.toStringAsPrecision not implemented";
}
String toRadixString(int radix) {
final table = const ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"A", "B", "C", "D", "E", "F"];
if ((radix <= 1) || (radix > 16)) {
throw "Bad radix: $radix";
}
final bool isNegative = this < 0;
var value = isNegative ? -this : this;
List temp = new List();
while (value > 0) {
var digit = value % radix;
value ~/= radix;
temp.add(digit);
}
if (temp.isEmpty()) {
return "0";
}
StringBuffer buffer = new StringBuffer();
if (isNegative) buffer.add("-");
for (int i = temp.length - 1; i >= 0; i--) {
buffer.add(table[temp[i]]);
}
return buffer.toString();
}
}
class Smi extends IntegerImplementation implements int {
int hashCode() {
return this;
}
int operator ~() native "Smi_bitNegate";
int sarFromInt(int other) native "Smi_sarFromInt";
int shlFromInt(int other) native "Smi_shlFromInt";
}
// Represents integers that cannot be represented by Smi but fit into 64bits.
class Mint extends IntegerImplementation implements int {
int hashCode() {
return this;
}
int operator ~() native "Mint_bitNegate";
}
// A number that can be represented as Smi or Mint will never be represented as
// Bigint.
class Bigint extends IntegerImplementation implements int {
int hashCode() {
return this;
}
int operator ~() native "Bigint_bitNegate";
// Shift by bigint exceeds range that can be handled by the VM.
int sarFromInt(int other) {
if (other < 0) {
return -1;
} else {
return 0;
}
}
int shlFromInt(int other) {
throw const OutOfMemoryException();
}
}

378
runtime/lib/isolate.cc Normal file
View file

@ -0,0 +1,378 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/bootstrap_natives.h"
#include "vm/assert.h"
#include "vm/class_finalizer.h"
#include "vm/dart.h"
#include "vm/dart_entry.h"
#include "vm/exceptions.h"
#include "vm/object.h"
#include "vm/object_store.h"
#include "vm/port.h"
#include "vm/resolver.h"
#include "vm/snapshot.h"
#include "vm/thread.h"
namespace dart {
class IsolateStartData {
public:
IsolateStartData(Isolate* isolate,
char* library_url,
char* class_name,
intptr_t port_id)
: isolate_(isolate),
library_url_(library_url),
class_name_(class_name),
port_id_(port_id) {}
Isolate* isolate_;
char* library_url_;
char* class_name_;
intptr_t port_id_;
};
static RawInstance* DeserializeMessage(void* data) {
// Create a snapshot object using the buffer.
Snapshot* snapshot = Snapshot::SetupFromBuffer(data);
ASSERT(snapshot->IsPartialSnapshot());
// Read object back from the snapshot.
Isolate* isolate= Isolate::Current();
SnapshotReader reader(snapshot, isolate->heap(), isolate->object_store());
Instance& instance = Instance::Handle();
instance ^= reader.ReadObject();
return instance.raw();
}
static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) {
void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size);
return reinterpret_cast<uint8_t*>(new_ptr);
}
static void* SerializeObject(const Instance& obj) {
uint8_t* result = NULL;
SnapshotWriter writer(false, &result, &allocator);
writer.WriteObject(obj.raw());
writer.FinalizeBuffer();
return result;
}
static void ProcessUnhandledException(const UnhandledException& uhe) {
const Instance& exception = Instance::Handle(uhe.exception());
Instance& string = Instance::Handle(DartLibraryCalls::ToString(exception));
const char* str = string.ToCString();
fprintf(stderr, "%s\n", str);
const Instance& stack = Instance::Handle(uhe.stacktrace());
string = DartLibraryCalls::ToString(stack);
str = string.ToCString();
fprintf(stderr, "%s\n", str);
exit(255);
}
static void ThrowErrorException(Exceptions::ExceptionType type,
const char* error_msg,
const char* library_url,
const char* class_name) {
String& str = String::Handle();
String& name = String::Handle();
str ^= String::New(error_msg);
name ^= String::NewSymbol(library_url);
str ^= String::Concat(str, name);
name ^= String::New(":");
str ^= String::Concat(str, name);
name ^= String::NewSymbol(class_name);
str ^= String::Concat(str, name);
GrowableArray<const Object*> arguments(1);
arguments.Add(&str);
Exceptions::ThrowByType(type, arguments);
}
RawInstance* ReceivePortCreate(intptr_t port_id) {
const String& class_name =
String::Handle(String::NewSymbol("ReceivePortImpl"));
const String& function_name = String::Handle(String::NewSymbol("create_"));
const int kNumArguments = 1;
const Array& kNoArgumentNames = Array::Handle();
const Function& function = Function::Handle(
Resolver::ResolveStatic(Library::Handle(Library::CoreLibrary()),
class_name,
function_name,
kNumArguments,
kNoArgumentNames,
Resolver::kIsQualified));
GrowableArray<const Object*> arguments(kNumArguments);
arguments.Add(&Integer::Handle(Integer::New(port_id)));
const Instance& result = Instance::Handle(
DartEntry::InvokeStatic(function, arguments));
if (result.IsUnhandledException()) {
UnhandledException& uhe = UnhandledException::Handle();
uhe ^= result.raw();
ProcessUnhandledException(uhe);
}
return result.raw();
}
static RawInstance* SendPortCreate(intptr_t port_id) {
const String& class_name = String::Handle(String::NewSymbol("SendPortImpl"));
const String& function_name = String::Handle(String::NewSymbol("create_"));
const int kNumArguments = 1;
const Array& kNoArgumentNames = Array::Handle();
const Function& function = Function::Handle(
Resolver::ResolveStatic(Library::Handle(Library::CoreLibrary()),
class_name,
function_name,
kNumArguments,
kNoArgumentNames,
Resolver::kIsQualified));
GrowableArray<const Object*> arguments(kNumArguments);
arguments.Add(&Integer::Handle(Integer::New(port_id)));
const Instance& result = Instance::Handle(
DartEntry::InvokeStatic(function, arguments));
return result.raw();
}
void PortMessage::Handle() {
const Instance& msg = Instance::Handle(DeserializeMessage(data()));
const String& class_name =
String::Handle(String::NewSymbol("ReceivePortImpl"));
const String& function_name =
String::Handle(String::NewSymbol("handleMessage_"));
const int kNumArguments = 3;
const Array& kNoArgumentNames = Array::Handle();
const Function& function = Function::Handle(
Resolver::ResolveStatic(Library::Handle(Library::CoreLibrary()),
class_name,
function_name,
kNumArguments,
kNoArgumentNames,
Resolver::kIsQualified));
GrowableArray<const Object*> arguments(kNumArguments);
arguments.Add(&Integer::Handle(Integer::New(dest_id())));
arguments.Add(&Integer::Handle(Integer::New(reply_id())));
arguments.Add(&msg);
const Object& result = Object::Handle(
DartEntry::InvokeStatic(function, arguments));
if (result.IsUnhandledException()) {
UnhandledException& uhe = UnhandledException::Handle();
uhe ^= result.raw();
ProcessUnhandledException(uhe);
}
ASSERT(result.IsNull());
}
static void RunIsolate(uword parameter) {
IsolateStartData* data = reinterpret_cast<IsolateStartData*>(parameter);
Isolate* isolate = data->isolate_;
char* library_url = data->library_url_;
char* class_name = data->class_name_;
intptr_t port_id = data->port_id_;
delete data;
Isolate::SetCurrent(isolate);
// Intialize stack limit in case we are running isolate in a
// different thread than in which it was initialized.
isolate->SetStackLimitFromCurrentTOS(reinterpret_cast<uword>(&isolate));
{
Zone zone;
HandleScope handle_scope;
ASSERT(ClassFinalizer::FinalizePendingClasses());
// Lookup the target class by name, create an instance and call the run
// method.
const String& lib_name = String::Handle(String::NewSymbol(library_url));
const Library& lib = Library::Handle(Library::LookupLibrary(lib_name));
ASSERT(!lib.IsNull());
const String& cls_name = String::Handle(String::NewSymbol(class_name));
const Class& target_class = Class::Handle(lib.LookupClass(cls_name));
// TODO(iposva): Deserialize or call the constructor after allocating.
// For now, we only support a non-parameterized or raw target class.
const Instance& target = Instance::Handle(Instance::New(target_class));
Instance& result = Instance::Handle();
// Invoke the default constructor.
const String& period = String::Handle(String::New("."));
String& constructor_name = String::Handle(String::Concat(cls_name, period));
const Function& default_constructor =
Function::Handle(target_class.LookupConstructor(constructor_name));
if (!default_constructor.IsNull()) {
GrowableArray<const Object*> arguments(1);
arguments.Add(&target);
result = DartEntry::InvokeStatic(default_constructor, arguments);
if (result.IsUnhandledException()) {
UnhandledException& uhe = UnhandledException::Handle();
uhe ^= result.raw();
ProcessUnhandledException(uhe);
}
ASSERT(result.IsNull());
}
// Invoke the "_run" method.
const Function& target_function = Function::Handle(Resolver::ResolveDynamic(
target, String::Handle(String::NewSymbol("_run")), 2, 0));
// TODO(iposva): Proper error checking here.
ASSERT(!target_function.IsNull());
// TODO(iposva): Allocate the proper port number here.
const Instance& local_port = Instance::Handle(ReceivePortCreate(port_id));
GrowableArray<const Object*> arguments(1);
arguments.Add(&local_port);
result = DartEntry::InvokeDynamic(target, target_function, arguments);
if (result.IsUnhandledException()) {
UnhandledException& uhe = UnhandledException::Handle();
uhe ^= result.raw();
ProcessUnhandledException(uhe);
}
ASSERT(result.IsNull());
}
free(class_name);
// Keep listening until there are no active receive ports.
while (isolate->active_ports() > 0) {
Zone zone;
HandleScope handle_scope;
PortMessage* message = PortMap::ReceiveMessage(0);
message->Handle();
delete message;
}
Dart::ShutdownIsolate();
}
static bool CheckArguments(const char* library_url, const char* class_name) {
Zone zone;
HandleScope handle_scope;
String& name = String::Handle();
if (!ClassFinalizer::FinalizePendingClasses()) {
return false;
}
// Lookup the target class by name, create an instance and call the run
// method.
name ^= String::NewSymbol(library_url);
const Library& lib = Library::Handle(Library::LookupLibrary(name));
if (lib.IsNull()) {
const String& error = String::Handle(
String::New("Error starting Isolate, library not loaded : "));
Isolate::Current()->object_store()->set_sticky_error(error);
return false;
}
name ^= String::NewSymbol(class_name);
const Class& target_class = Class::Handle(lib.LookupClass(name));
if (target_class.IsNull()) {
const String& error = String::Handle(
String::New("Error starting Isolate, class not loaded : "));
Isolate::Current()->object_store()->set_sticky_error(error);
return false;
}
return true; // No errors.
}
DEFINE_NATIVE_ENTRY(IsolateNatives_start, 2) {
Isolate* preserved_isolate = Isolate::Current();
const Instance& runnable = Instance::CheckedHandle(arguments->At(0));
const Class& runnable_class = Class::Handle(runnable.clazz());
const char* class_name = String::Handle(runnable_class.Name()).ToCString();
const Library& library = Library::Handle(runnable_class.library());
ASSERT(!library.IsNull());
const char* library_url = String::Handle(library.url()).ToCString();
intptr_t port_id = 0;
const char* error_msg = NULL;
Isolate* spawned_isolate =
Dart::CreateIsolate(NULL, preserved_isolate->init_callback_data());
if (spawned_isolate != NULL) {
// Check arguments to see if the specified library and classes are
// loaded, this check will throw an exception if they are not loaded.
if (CheckArguments(library_url, class_name)) {
port_id = PortMap::CreatePort();
uword data = reinterpret_cast<uword>(
new IsolateStartData(spawned_isolate,
strdup(library_url),
strdup(class_name),
port_id));
new Thread(RunIsolate, data);
} else {
// Error loading application into spawned isolate, shut it down and
// report error.
// Make sure to grab the error message out of the isolate before it has
// been shutdown and to allocate it in the preserved isolates zone.
{
Zone zone;
HandleScope scope;
const String& error = String::Handle(
spawned_isolate->object_store()->sticky_error());
const char* temp_error_msg = error.ToCString();
intptr_t err_len = strlen(temp_error_msg) + 1;
Zone* preserved_zone = preserved_isolate->current_zone();
error_msg = reinterpret_cast<char*>(preserved_zone->Allocate(err_len));
OS::SNPrint(
const_cast<char*>(error_msg), err_len, "%s", temp_error_msg);
}
Dart::ShutdownIsolate();
spawned_isolate = NULL;
}
} else {
error_msg = "Creation of Isolate failed : ";
}
// Switch back to the original isolate and return.
Isolate::SetCurrent(preserved_isolate);
if (spawned_isolate == NULL) {
// Unable to spawn isolate correctly, throw exception.
ASSERT(error_msg != NULL);
ThrowErrorException(Exceptions::kIllegalArgument,
error_msg,
library_url,
class_name);
}
const Instance& port = Instance::Handle(SendPortCreate(port_id));
if (port.IsUnhandledException()) {
ThrowErrorException(Exceptions::kInternalError,
"Unable to create send port to isolate",
library_url,
class_name);
}
arguments->SetReturn(port);
}
DEFINE_NATIVE_ENTRY(ReceivePortImpl_factory, 1) {
ASSERT(TypeArguments::CheckedHandle(arguments->At(0)).IsNull());
intptr_t port_id = PortMap::CreatePort();
const Instance& port = Instance::Handle(ReceivePortCreate(port_id));
arguments->SetReturn(port);
}
DEFINE_NATIVE_ENTRY(ReceivePortImpl_closeInternal, 1) {
intptr_t id = Smi::CheckedHandle(arguments->At(0)).Value();
PortMap::ClosePort(id);
}
DEFINE_NATIVE_ENTRY(SendPortImpl_sendInternal_, 3) {
intptr_t send_id = Smi::CheckedHandle(arguments->At(0)).Value();
intptr_t reply_id = Smi::CheckedHandle(arguments->At(1)).Value();
// TODO(iposva): Allow for arbitrary messages to be sent.
void* data = SerializeObject(Instance::CheckedHandle(arguments->At(2)));
PortMessage* message = new PortMessage(send_id, reply_id, data);
PortMap::PostMessage(message);
}
} // namespace dart

166
runtime/lib/isolate.dart Normal file
View file

@ -0,0 +1,166 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
class ReceivePortFactory {
factory ReceivePort() {
return new ReceivePortImpl();
}
factory ReceivePort.singleShot() {
return new ReceivePortSingleShotImpl();
}
}
class ReceivePortImpl implements ReceivePort {
/*--- public interface ---*/
factory ReceivePortImpl() native "ReceivePortImpl_factory";
receive(void onMessage(var message, SendPort replyTo)) {
_onMessage = onMessage;
}
close() {
_portMap.remove(_id);
_closeInternal(_id);
}
SendPort toSendPort() {
return new SendPortImpl(_id);
}
/**** Internal implementation details ****/
// Called from the VM to create a new ReceivePort instance.
static ReceivePortImpl create_(int id) {
return new ReceivePortImpl._internal(id);
}
ReceivePortImpl._internal(int id) : _id = id {
if (_portMap === null) {
_portMap = new Map();
}
_portMap[id] = this;
}
// Called from the VM to dispatch to the handler.
static void handleMessage_(int id, int replyId, var message) {
assert(_portMap != null);
ReceivePort port = _portMap[id];
SendPort replyTo = (replyId == 0) ? null : new SendPortImpl(replyId);
(port._onMessage)(message, replyTo);
PromiseQueue.process();
}
// Call into the VM to close the VM maintained mappings.
static _closeInternal(int id) native "ReceivePortImpl_closeInternal";
final int _id;
var _onMessage;
// id to ReceivePort mapping.
static Map _portMap;
}
class ReceivePortSingleShotImpl implements ReceivePort {
ReceivePortSingleShotImpl() : _port = new ReceivePortImpl() { }
void receive(void callback(var message, SendPort replyTo)) {
_port.receive((var message, SendPort replyTo) {
_port.close();
callback(message, replyTo);
});
}
void close() {
_port.close();
}
SendPort toSendPort() {
return _port.toSendPort();
}
final ReceivePortImpl _port;
}
class SendPortImpl implements SendPort {
/*--- public interface ---*/
void send(var message, SendPort replyTo) {
if (PromiseQueue.isEmpty()) {
this._sendNow(message, replyTo);
} else {
_enqueueSend(message, replyTo);
}
}
void _enqueueSend(var message, SendPort replyTo) {
PromiseQueue.enqueue(const []).then((ignored) {
this._sendNow(message, replyTo);
});
}
void _sendNow(var message, SendPort replyTo) {
int replyId = (replyTo === null) ? 0 : replyTo._id;
_sendInternal(_id, replyId, message);
}
ReceivePortSingleShotImpl call(var message) {
final result = new ReceivePortSingleShotImpl();
this.send(message, result.toSendPort());
return result;
}
ReceivePortSingleShotImpl _callNow(var message) {
final result = new ReceivePortSingleShotImpl();
this._sendNow(message, result.toSendPort());
return result;
}
bool operator==(var other) {
return (other is SendPortImpl) && _id == other._id;
}
int hashCode() {
return _id;
}
/*--- private implementation ---*/
const SendPortImpl(int id) : _id = id;
// SendPortImpl.create_ is called from the VM when a new SendPort instance is
// needed by the VM code.
static SendPort create_(int id) {
return new SendPortImpl(id);
}
// Forward the implementation of sending messages to the VM. Only port ids
// are being handed to the VM.
static _sendInternal(int sendId, int replyId, var message)
native "SendPortImpl_sendInternal_";
final int _id;
}
class IsolateNatives {
static Promise<SendPort> spawn(Isolate isolate, bool isLight) {
Promise<SendPort> result = new Promise<SendPort>();
SendPort port = _start(isolate, isLight);
result.complete(port);
return result;
}
// Starts a new isolate calling the run method on a new instance of the
// remote class's type.
// Returns the send port which is passed to the newly created isolate.
// This method is being dispatched to from the public core library code.
static SendPort _start(Isolate isolate, bool light)
native "IsolateNatives_start";
// The VM knows in which isolate the function must be run, therefore
// there is no need for wrapping it.
static Function bind(Function f) { return f; }
}

View file

@ -0,0 +1,34 @@
# Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
# Implementation sources.
{
'sources': [
'array.cc',
'array.dart',
'arrays.dart',
'bool.dart',
'collections.dart',
'date_time.cc',
'date_time.dart',
'double.cc',
'double.dart',
'growable_array.dart',
'immutable_map.dart',
'integers.cc',
'integers.dart',
'isolate.cc',
'isolate.dart',
'math.dart',
'math.cc',
'regexp.cc',
'regexp_jsc.cc',
'regexp_jsc.h',
'regexp.dart',
'string.cc',
'string.dart',
'string_buffer.dart',
],
}

View file

@ -0,0 +1,17 @@
# Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
# Sources visible to via default library.
{
'sources': [
'clock.cc',
'clock.dart',
'error.cc',
'error.dart',
'error.h',
'object.cc',
'object.dart',
],
}

183
runtime/lib/math.cc Normal file
View file

@ -0,0 +1,183 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include <ctype.h> // isspace.
#include "vm/bootstrap_natives.h"
#include "vm/bigint_operations.h"
#include "vm/exceptions.h"
#include "vm/native_entry.h"
#include "vm/object.h"
#include "vm/random.h"
#include "vm/scanner.h"
namespace dart {
DEFINE_NATIVE_ENTRY(MathNatives_sqrt, 1) {
const double operand = Double::CheckedHandle(arguments->At(0)).value();
arguments->SetReturn(Double::Handle(Double::New(sqrt(operand))));
}
DEFINE_NATIVE_ENTRY(MathNatives_sin, 1) {
const double operand = Double::CheckedHandle(arguments->At(0)).value();
arguments->SetReturn(Double::Handle(Double::New(sin(operand))));
}
DEFINE_NATIVE_ENTRY(MathNatives_cos, 1) {
const double operand = Double::CheckedHandle(arguments->At(0)).value();
arguments->SetReturn(Double::Handle(Double::New(cos(operand))));
}
DEFINE_NATIVE_ENTRY(MathNatives_tan, 1) {
const double operand = Double::CheckedHandle(arguments->At(0)).value();
arguments->SetReturn(Double::Handle(Double::New(tan(operand))));
}
DEFINE_NATIVE_ENTRY(MathNatives_asin, 1) {
const double operand = Double::CheckedHandle(arguments->At(0)).value();
arguments->SetReturn(Double::Handle(Double::New(asin(operand))));
}
DEFINE_NATIVE_ENTRY(MathNatives_acos, 1) {
const double operand = Double::CheckedHandle(arguments->At(0)).value();
arguments->SetReturn(Double::Handle(Double::New(acos(operand))));
}
DEFINE_NATIVE_ENTRY(MathNatives_atan, 1) {
const double operand = Double::CheckedHandle(arguments->At(0)).value();
arguments->SetReturn(Double::Handle(Double::New(atan(operand))));
}
// It is not possible to call the native MathNatives_atan2. Somehow this leads
// to a dynamic error "native function 'MathNatives_atan2' cannot be found".
DEFINE_NATIVE_ENTRY(MathNatives_2atan, 2) {
const double operand1 = Double::CheckedHandle(arguments->At(0)).value();
const double operand2 = Double::CheckedHandle(arguments->At(1)).value();
arguments->SetReturn(Double::Handle(Double::New(atan2(operand1, operand2))));
}
DEFINE_NATIVE_ENTRY(MathNatives_exp, 1) {
const double operand = Double::CheckedHandle(arguments->At(0)).value();
arguments->SetReturn(Double::Handle(Double::New(exp(operand))));
}
DEFINE_NATIVE_ENTRY(MathNatives_log, 1) {
const double operand = Double::CheckedHandle(arguments->At(0)).value();
arguments->SetReturn(Double::Handle(Double::New(log(operand))));
}
DEFINE_NATIVE_ENTRY(MathNatives_random, 0) {
arguments->SetReturn(Double::Handle(Double::
New(static_cast<double>(Random::RandomInt32()-1)/0x80000000)));
}
// TODO(srdjan): Investigate for performance hit; the integer and double parsing
// may not be efficient as we need to generate two extra growable arrays.
static bool IsValidLiteral(const Scanner::GrowableTokenStream& tokens,
Token::Kind literal_kind,
bool* is_positive,
String** value) {
if ((tokens.length() == 2) &&
(tokens[0].kind == literal_kind) &&
(tokens[1].kind == Token::kEOS)) {
*is_positive = true;
*value = tokens[0].literal;
return true;
}
if ((tokens.length() == 3) &&
((tokens[0].kind == Token::kADD) || (tokens[0].kind == Token::kSUB)) &&
(tokens[1].kind == literal_kind) &&
(tokens[2].kind == Token::kEOS)) {
// Check there is no space between "+/-" and number.
if ((tokens[0].offset + 1) != tokens[1].offset) {
return false;
}
*is_positive = tokens[0].kind == Token::kADD;
*value = tokens[1].literal;
return true;
}
return false;
}
DEFINE_NATIVE_ENTRY(MathNatives_parseInt, 1) {
const String& value = String::CheckedHandle(arguments->At(0));
Scanner scanner(value, String::Handle());
const Scanner::GrowableTokenStream& tokens = scanner.GetStream();
String* int_string;
bool is_positive;
if (IsValidLiteral(tokens, Token::kINTEGER, &is_positive, &int_string)) {
Integer& result = Integer::Handle();
if (is_positive) {
result = Integer::New(*int_string);
} else {
String& temp = String::Handle();
temp = String::Concat(String::Handle(String::NewSymbol("-")),
*int_string);
result = Integer::New(temp);
}
arguments->SetReturn(result);
} else {
GrowableArray<const Object*> args;
args.Add(&value);
Exceptions::ThrowByType(Exceptions::kBadNumberFormat, args);
}
}
DEFINE_NATIVE_ENTRY(MathNatives_parseDouble, 1) {
const String& value = String::CheckedHandle(arguments->At(0));
Scanner scanner(value, String::Handle());
const Scanner::GrowableTokenStream& tokens = scanner.GetStream();
String* number_string;
bool is_positive;
if (IsValidLiteral(tokens, Token::kDOUBLE, &is_positive, &number_string)) {
const char* cstr = number_string->ToCString();
char* p_end = NULL;
double double_value = strtod(cstr, &p_end);
ASSERT(p_end != cstr);
if (!is_positive) {
double_value = -double_value;
}
Double& result = Double::Handle(Double::New(double_value));
arguments->SetReturn(result);
return;
}
if (IsValidLiteral(tokens, Token::kINTEGER, &is_positive, &number_string)) {
Integer& res = Integer::Handle(Integer::New(*number_string));
if (is_positive) {
arguments->SetReturn(Double::Handle(Double::New(res.AsDoubleValue())));
} else {
arguments->SetReturn(Double::Handle(Double::New(-res.AsDoubleValue())));
}
return;
}
// Infinity and nan.
if (IsValidLiteral(tokens, Token::kIDENT, &is_positive, &number_string)) {
const char* kNan = "NaN";
const char* kInfinity = "Infinity";
if (number_string->Equals(kNan, strlen(kNan))) {
arguments->SetReturn(Double::Handle(Double::New(NAN)));
return;
}
if (number_string->Equals(kInfinity, strlen(kInfinity))) {
if (is_positive) {
arguments->SetReturn(Double::Handle(Double::New(INFINITY)));
} else {
arguments->SetReturn(Double::Handle(Double::New(-INFINITY)));
}
return;
}
}
GrowableArray<const Object*> args;
args.Add(&value);
Exceptions::ThrowByType(Exceptions::kBadNumberFormat, args);
}
} // namespace dart

78
runtime/lib/math.dart Normal file
View file

@ -0,0 +1,78 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
class MathNatives {
static int parseInt(String str) {
if (str is !String) {
throw "Wrong argument";
}
return _parseInt(str);
}
static double parseDouble(String str) {
if (str is !String) {
throw "Wrong argument";
}
return _parseDouble(str);
}
static double sqrt(num value) {
return _sqrt(_asDouble(value));
}
static double sin(num value) {
return _sin(_asDouble(value));
}
static double cos(num value) {
return _cos(_asDouble(value));
}
static double tan(num value) {
return _tan(_asDouble(value));
}
static double acos(num value) {
return _acos(_asDouble(value));
}
static double asin(num value) {
return _asin(_asDouble(value));
}
static double atan(num value) {
return _atan(_asDouble(value));
}
static double atan2(num a, num b) {
return _atan2(_asDouble(a), _asDouble(b));
}
static double exp(num value) {
return _exp(_asDouble(value));
}
static double log(num value) {
return _log(_asDouble(value));
}
static num pow(num value, num exponent) {
if (exponent is int) {
return value.pow(exponent);
}
// Double.pow will call exponent.toDouble().
return _asDouble(value).pow(exponent);
}
static double random() {
return _random();
}
static double _asDouble(num value) {
double result = value.toDouble();
if (result is !double) {
throw "Wrong argument";
}
return result;
}
static double _random() native "MathNatives_random";
static double _sqrt(double value) native "MathNatives_sqrt";
static double _sin(double value) native "MathNatives_sin";
static double _cos(double value) native "MathNatives_cos";
static double _tan(double value) native "MathNatives_tan";
static double _acos(double value) native "MathNatives_acos";
static double _asin(double value) native "MathNatives_asin";
static double _atan(double value) native "MathNatives_atan";
static double _atan2(double a, double b) native "MathNatives_2atan";
static double _exp(double value) native "MathNatives_exp";
static double _log(double value) native "MathNatives_log";
static int _parseInt(String str) native "MathNatives_parseInt";
static double _parseDouble(String str) native "MathNatives_parseDouble";
}

35
runtime/lib/object.cc Normal file
View file

@ -0,0 +1,35 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/bootstrap_natives.h"
#include "vm/exceptions.h"
#include "vm/native_entry.h"
#include "vm/object.h"
namespace dart {
DEFINE_NATIVE_ENTRY(Object_toString, 1) {
const Instance& instance = Instance::CheckedHandle(arguments->At(0));
const char* c_str = instance.ToCString();
arguments->SetReturn(String::Handle(String::New(c_str)));
}
DEFINE_NATIVE_ENTRY(Object_noSuchMethod, 3) {
const Instance& instance = Instance::CheckedHandle(arguments->At(0));
const String& function_name = String::CheckedHandle(arguments->At(1));
const Array& func_args = Array::CheckedHandle(arguments->At(2));
if (instance.IsNull()) {
GrowableArray<const Object*> args;
Exceptions::ThrowByType(Exceptions::kNullPointer, args);
}
GrowableArray<const Object*> dart_arguments(3);
dart_arguments.Add(&instance);
dart_arguments.Add(&function_name);
dart_arguments.Add(&func_args);
Exceptions::ThrowByType(Exceptions::kNoSuchMethod, dart_arguments);
}
} // namespace dart

17
runtime/lib/object.dart Normal file
View file

@ -0,0 +1,17 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
class Object {
const Object();
String toString() native "Object_toString";
bool operator ==(other) {
return this === other;
}
void noSuchMethod(String function_name, Array args) native "Object_noSuchMethod";
/**
* Return this object without type information.
*/
get dynamic() { return this; }
}

65
runtime/lib/regexp.cc Normal file
View file

@ -0,0 +1,65 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/bootstrap_natives.h"
#include "vm/assert.h"
#include "vm/exceptions.h"
#include "vm/native_entry.h"
#include "vm/object.h"
#include "lib/regexp_jsc.h"
namespace dart {
DEFINE_NATIVE_ENTRY(JSSyntaxRegExp_factory, 3) {
ASSERT(TypeArguments::CheckedHandle(arguments->At(0)).IsNull());
const String& pattern = String::CheckedHandle(arguments->At(1));
const String& flags = String::CheckedHandle(arguments->At(2));
const JSRegExp& new_regex = JSRegExp::Handle(Jscre::Compile(pattern, flags));
arguments->SetReturn(new_regex);
}
DEFINE_NATIVE_ENTRY(JSSyntaxRegExp_getPattern, 1) {
const JSRegExp& regexp = JSRegExp::CheckedHandle(arguments->At(0));
const String& result = String::Handle(regexp.pattern());
arguments->SetReturn(result);
}
DEFINE_NATIVE_ENTRY(JSSyntaxRegExp_getFlags, 1) {
const JSRegExp& regexp = JSRegExp::CheckedHandle(arguments->At(0));
const String& result = String::Handle(String::New(regexp.Flags()));
arguments->SetReturn(result);
}
DEFINE_NATIVE_ENTRY(JSSyntaxRegExp_getGroupCount, 1) {
const JSRegExp& regexp = JSRegExp::CheckedHandle(arguments->At(0));
if (regexp.is_initialized()) {
const Smi& result = Smi::Handle(regexp.num_bracket_expressions());
arguments->SetReturn(result);
return;
}
const String& pattern = String::Handle(regexp.pattern());
const String& errmsg =
String::Handle(String::New("Regular expression is not initialized yet"));
GrowableArray<const Object*> args;
args.Add(&pattern);
args.Add(&errmsg);
Exceptions::ThrowByType(Exceptions::kIllegalJSRegExp, args);
}
DEFINE_NATIVE_ENTRY(JSSyntaxRegExp_ExecuteMatch, 3) {
const JSRegExp& regexp = JSRegExp::CheckedHandle(arguments->At(0));
const String& str = String::CheckedHandle(arguments->At(1));
const Smi& start_index = Smi::CheckedHandle(arguments->At(2));
const Array& result =
Array::Handle(Jscre::Execute(regexp, str, start_index.Value()));
arguments->SetReturn(result);
}
} // namespace dart

101
runtime/lib/regexp.dart Normal file
View file

@ -0,0 +1,101 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
class JSRegExpMatch implements Match {
JSRegExpMatch(this.regexp, this.str, this._match);
int start() {
return _start(0);
}
int end() {
return _end(0);
}
int _start(int group) {
return _match[(group * _kMatchPair)];
}
int _end(int group) {
return _match[(group * _kMatchPair) + 1];
}
String group(int group) {
return str.substringUnchecked_(_start(group), _end(group));
}
String operator [](int group) {
return str.substringUnchecked_(_start(group), _end(group));
}
List<String> groups(List<int> groups) {
var groupsList = new List<String>(groups.length);
for (int i = 0; i < groups.length; i++) {
int grp_idx = groups[i];
groupsList[i] = str.substringUnchecked_(_start(grp_idx), _end(grp_idx));
}
return groupsList;
}
int groupCount() {
return regexp._groupCount;
}
final RegExp regexp;
final String str;
final List<int> _match;
static final int _kMatchPair = 2;
}
class JSSyntaxRegExp implements RegExp {
const factory JSSyntaxRegExp(String pattern, String flags)
native "JSSyntaxRegExp_factory";
Match firstMatch(String str) {
List match = _ExecuteMatch(str, 0);
if (match === null) {
return null;
}
return new JSRegExpMatch(this, str, match);
}
Iterable<Match> allMatches(String str) {
var jsregexMatches = new GrowableObjectArray<JSRegExpMatch>();
List match = _ExecuteMatch(str, 0);
if (match !== null) {
jsregexMatches.add(new JSRegExpMatch(this, str, match));
while (true) {
match = _ExecuteMatch(str, match[1]);
if (match === null) {
break;
}
jsregexMatches.add(new JSRegExpMatch(this, str, match));
}
}
return jsregexMatches;
}
bool hasMatch(String str) {
List match = _ExecuteMatch(str, 0);
return (match === null) ? false : true;
}
String stringMatch(String str) {
List match = _ExecuteMatch(str, 0);
if (match === null) {
return null;
}
return str.substringUnchecked_(match[0], match[1]);
}
String get pattern() native "JSSyntaxRegExp_getPattern";
String get flags() native "JSSyntaxRegExp_getFlags";
int get _groupCount() native "JSSyntaxRegExp_getGroupCount";
List _ExecuteMatch(String str, int start_index)
native "JSSyntaxRegExp_ExecuteMatch";
}

187
runtime/lib/regexp_jsc.cc Normal file
View file

@ -0,0 +1,187 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// This file encapsulates all the interaction with the
// JSC regular expression library also referred to as pcre
#include "lib/regexp_jsc.h"
#include "vm/allocation.h"
#include "vm/assert.h"
#include "vm/exceptions.h"
#include "vm/globals.h"
#include "vm/isolate.h"
#include "third_party/jscre/pcre.h"
namespace dart {
static uint16_t* GetTwoByteData(const String& str) {
intptr_t size = str.Length() * sizeof(uint16_t);
Zone* zone = Isolate::Current()->current_zone();
uint16_t* two_byte_str = reinterpret_cast<uint16_t*>(zone->Allocate(size));
for (intptr_t i = 0; i < str.Length(); i++) {
two_byte_str[i] = str.CharAt(i);
}
return two_byte_str;
}
static void* JSREMalloc(size_t size) {
intptr_t regexp_size = static_cast<intptr_t>(size);
ASSERT(regexp_size > 0);
const JSRegExp& new_regex = JSRegExp::Handle(JSRegExp::New(size));
return new_regex.GetDataStartAddress();
}
static void JSREFree(void* ptr) {
USE(ptr); // Do nothing, memory is garbage collected.
}
static void ThrowExceptionOnError(const String& pattern,
const char* error_msg) {
if (error_msg == NULL) {
error_msg = "Unknown regexp compile error";
}
const String& errmsg = String::Handle(String::New(error_msg));
GrowableArray<const Object*> args;
args.Add(&pattern);
args.Add(&errmsg);
Exceptions::ThrowByType(Exceptions::kIllegalJSRegExp, args);
}
RawJSRegExp* Jscre::Compile(const String& pattern, const String& flags) {
// First convert the pattern to UTF16 format as the jscre library expects
// strings to be in UTF16 encoding.
uint16_t* two_byte_pattern = GetTwoByteData(pattern);
// Parse the flags.
jscre::JSRegExpIgnoreCaseOption ignore_case = jscre::JSRegExpDoNotIgnoreCase;
// A Dart regexp is always global.
bool is_global = true;
jscre::JSRegExpMultilineOption multi_line = jscre::JSRegExpSingleLine;
for (int i = 0; i < flags.Length(); i++) {
switch (flags.CharAt(i)) {
case 'i':
ignore_case = jscre::JSRegExpIgnoreCase;
break;
case 'm':
multi_line = jscre::JSRegExpMultiline;
break;
default:
// Unrecognized flag, throw an exception.
ThrowExceptionOnError(pattern,
"Unknown flag specified for regular expression");
UNREACHABLE();
return JSRegExp::null();
}
}
// Compile the regex by calling into the jscre library.
uint32_t num_bracket_expressions = 0;
const char* error_msg = NULL;
jscre::JSRegExp* jscregexp = jscre::jsRegExpCompile(two_byte_pattern,
pattern.Length(),
ignore_case,
multi_line,
&num_bracket_expressions,
&error_msg,
&JSREMalloc,
&JSREFree);
if (jscregexp == NULL) {
// There was an error compiling the regex, Throw an exception.
ThrowExceptionOnError(pattern, error_msg);
UNREACHABLE();
return JSRegExp::null();
} else {
// Setup the compiled regex object and return it.
JSRegExp& regexp =
JSRegExp::Handle(JSRegExp::FromDataStartAddress(jscregexp));
regexp.set_pattern(pattern);
if (multi_line == jscre::JSRegExpMultiline) {
regexp.set_is_multi_line();
}
if (ignore_case == jscre::JSRegExpIgnoreCase) {
regexp.set_is_ignore_case();
}
if (is_global) {
regexp.set_is_global();
}
regexp.set_is_complex(); // Always use jscre library.
regexp.set_num_bracket_expressions(num_bracket_expressions);
return regexp.raw();
}
}
RawArray* Jscre::Execute(const JSRegExp& regex,
const String& str,
intptr_t start_index) {
// First convert the input str to UTF16 format as the jscre library expects
// strings to be in UTF16 encoding.
uint16_t* two_byte_str = GetTwoByteData(str);
// Execute a regex match by calling into the jscre library.
jscre::JSRegExp* jscregexp =
reinterpret_cast<jscre::JSRegExp*>(regex.GetDataStartAddress());
ASSERT(jscregexp != NULL);
const Smi& num_bracket_exprs = Smi::Handle(regex.num_bracket_expressions());
intptr_t num_bracket_expressions = num_bracket_exprs.Value();
Zone* zone = Isolate::Current()->current_zone();
// The jscre library rounds the passed in size to a multiple of 3 in order
// to reuse the passed in offsets array as a temporary chunk of working
// storage during matching, so we just pass in a size which is a multiple
// of 3.
const int kJscreMultiple = 3;
int offsets_length = (num_bracket_expressions + 1) * kJscreMultiple;
int* offsets = NULL;
int offsets_array_size = offsets_length * sizeof(offsets[0]);
offsets = reinterpret_cast<int*>(zone->Allocate(offsets_array_size));
int retval = jscre::jsRegExpExecute(jscregexp,
two_byte_str,
str.Length(),
start_index,
offsets,
offsets_length);
// The KJS JavaScript engine returns null (ie, a failed match) when
// JSRE's internal match limit is exceeded. We duplicate that behavior here.
if (retval == jscre::JSRegExpErrorNoMatch
|| retval == jscre::JSRegExpErrorHitLimit) {
return Array::null();
}
// Other JSRE errors:
if (retval < 0) {
const String& pattern = String::Handle(regex.pattern());
const int kErrorLength = 256;
char error_msg[kErrorLength];
OS::SNPrint(error_msg, kErrorLength,
"jscre::jsRegExpExecute error : %d", retval);
ThrowExceptionOnError(pattern, error_msg);
UNREACHABLE();
return Array::null();
}
const int kMatchPair = 2;
Array& array =
Array::Handle(Array::New(kMatchPair * (num_bracket_expressions + 1)));
// The matches come in (start, end + 1) pairs for each bracketted expression.
Smi& start = Smi::Handle();
Smi& end = Smi::Handle();
for (intptr_t i = 0;
i < (kMatchPair * (num_bracket_expressions + 1));
i += kMatchPair) {
start = Smi::New(offsets[i]);
end = Smi::New(offsets[i + 1]);
array.SetAt(i, start);
array.SetAt(i+1, end);
}
return array.raw();
}
} // namespace dart

23
runtime/lib/regexp_jsc.h Normal file
View file

@ -0,0 +1,23 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef LIB_REGEXP_JSC_H_
#define LIB_REGEXP_JSC_H_
#include "vm/object.h"
namespace dart {
class Jscre : public AllStatic {
public:
static RawJSRegExp* Compile(const String& pattern, const String& flags);
static RawArray* Execute(const JSRegExp& regex,
const String& str,
intptr_t index);
};
} // namespace dart
#endif // LIB_REGEXP_JSC_H_

150
runtime/lib/string.cc Normal file
View file

@ -0,0 +1,150 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/bootstrap_natives.h"
#include "vm/exceptions.h"
#include "vm/native_entry.h"
#include "vm/object.h"
namespace dart {
DEFINE_NATIVE_ENTRY(StringBase_createFromCodePoints, 1) {
const Array& a = Array::CheckedHandle(arguments->At(0));
// TODO(srdjan): Check that parameterized type is an int.
Zone* zone = Isolate::Current()->current_zone();
intptr_t len = a.Length();
// Unbox the array and determine the maximum element width.
bool is_one_byte_string = true;
bool is_two_byte_string = true;
uint32_t* temp = reinterpret_cast<uint32_t*>(
zone->Allocate(len * sizeof(uint32_t))); // NOLINT
Smi& element = Smi::Handle();
for (intptr_t i = 0; i < len; i++) {
const Object& index_object = Object::Handle(a.At(i));
if (!index_object.IsSmi()) {
GrowableArray<const Object*> args;
args.Add(&index_object);
Exceptions::ThrowByType(Exceptions::kIllegalArgument, args);
}
element ^= index_object.raw();
intptr_t value = element.Value();
if (value < 0) {
GrowableArray<const Object*> args;
Exceptions::ThrowByType(Exceptions::kIllegalArgument, args);
} else if (value > 0xFFFF) {
is_one_byte_string = false;
is_two_byte_string = false;
} else if (value > 0xFF) {
is_one_byte_string = false;
}
temp[i] = value;
}
String& result = String::Handle();
if (is_one_byte_string) {
result ^= OneByteString::New(temp, len, Heap::kNew);
} else if (is_two_byte_string) {
result ^= TwoByteString::New(temp, len, Heap::kNew);
} else {
result ^= FourByteString::New(temp, len, Heap::kNew);
}
arguments->SetReturn(result);
}
DEFINE_NATIVE_ENTRY(String_hashCode, 1) {
const String& str = String::CheckedHandle(arguments->At(0));
intptr_t hash_val = 0;
if (!str.IsNull()) {
hash_val = str.Hash();
}
ASSERT(Smi::IsValid(hash_val));
ASSERT(hash_val > 0);
const Smi& hash_smi = Smi::Handle(Smi::New(hash_val));
arguments->SetReturn(hash_smi);
}
DEFINE_NATIVE_ENTRY(String_getLength, 1) {
const String& str = String::CheckedHandle(arguments->At(0));
arguments->SetReturn(Smi::Handle(Smi::New(str.Length())));
}
static int32_t StringValueAt(const String& str, const Integer& index) {
if (index.IsSmi()) {
Smi& smi = Smi::Handle();
smi ^= index.raw();
int32_t index = smi.Value();
if ((index < 0) || (index >= str.Length())) {
GrowableArray<const Object*> arguments;
arguments.Add(&smi);
Exceptions::ThrowByType(Exceptions::kIndexOutOfRange, arguments);
}
return str.CharAt(index);
} else {
// TODO(srdjan): Bigint index not supported.
UNIMPLEMENTED();
return 0;
}
}
DEFINE_NATIVE_ENTRY(String_charAt, 2) {
const String& str = String::CheckedHandle(arguments->At(0));
const Instance& index_instance = Instance::CheckedHandle(arguments->At(1));
if (!index_instance.IsInteger()) {
GrowableArray<const Object*> args;
args.Add(&index_instance);
Exceptions::ThrowByType(Exceptions::kIllegalArgument, args);
}
Integer& index = Integer::Handle();
index ^= index_instance.raw();
uint32_t value = StringValueAt(str, index);
ASSERT(value <= 0x10FFFF);
arguments->SetReturn(String::Handle(String::NewSymbol(&value, 1)));
}
DEFINE_NATIVE_ENTRY(String_charCodeAt, 2) {
const String& str = String::CheckedHandle(arguments->At(0));
const Integer& index_instance = Integer::CheckedHandle(arguments->At(1));
if (!index_instance.IsInteger()) {
GrowableArray<const Object*> args;
args.Add(&index_instance);
Exceptions::ThrowByType(Exceptions::kIllegalArgument, args);
}
Integer& index = Integer::Handle();
index ^= index_instance.raw();
int32_t value = StringValueAt(str, index);
ASSERT(value >= 0);
ASSERT(value <= 0x10FFFF);
arguments->SetReturn(Smi::Handle(Smi::New(value)));
}
DEFINE_NATIVE_ENTRY(String_concat, 2) {
const String& a = String::CheckedHandle(arguments->At(0));
ASSERT(!a.IsNull()); // The receiver cannot be null.
const Instance& b_instance = Instance::CheckedHandle(arguments->At(1));
if (!b_instance.IsString()) {
GrowableArray<const Object*> args;
Exceptions::ThrowByType(Exceptions::kIllegalArgument, args);
}
String& b = String::Handle();
b ^= b_instance.raw();
const String& result = String::Handle(String::Concat(a, b));
arguments->SetReturn(result);
}
DEFINE_NATIVE_ENTRY(Strings_concatAll, 1) {
const Array& strings = Array::CheckedHandle(arguments->At(0));
ASSERT(!strings.IsNull());
const String& result = String::Handle(String::ConcatAll(strings));
arguments->SetReturn(result);
}
} // namespace dart

483
runtime/lib/string.dart Normal file
View file

@ -0,0 +1,483 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/**
* [StringBase] contains common methods used by concrete String implementations,
* e.g., OneByteString.
*/
class StringBase {
int hashCode() native "String_hashCode";
/**
* Create the most efficient string representation for specified
* [codePoints].
*/
static String createFromCharCodes(List<int> charCodes) {
ObjectArray objectArray;
if (charCodes is ObjectArray) {
objectArray = charCodes;
} else {
int len = charCodes.length;
objectArray = new Array(len);
for (int i = 0; i < len; i++) {
objectArray[i] = charCodes[i];
}
}
return _createFromCodePoints(objectArray);
}
static String _createFromCodePoints(ObjectArray<int> codePoints)
native "StringBase_createFromCodePoints";
String operator [](int index) native "String_charAt";
int charCodeAt(int index) native "String_charCodeAt";
int get length() native "String_getLength";
bool isEmpty() {
return this.length === 0;
}
String concat(String other) native "String_concat";
String toString() {
return this;
}
bool operator ==(Object other) {
if (this === other) {
return true;
}
if (!(other is String) ||
(this.length != other.length)) {
// TODO(5413632): Compare hash codes when both are present.
return false;
}
return this.compareTo(other) === 0;
}
int compareTo(String other) {
int thisLength = this.length;
int otherLength = other.length;
int len = (thisLength < otherLength) ? thisLength : otherLength;
for (int i = 0; i < len; i++) {
int thisCodePoint = this.charCodeAt(i);
int otherCodePoint = other.charCodeAt(i);
if (thisCodePoint < otherCodePoint) {
return -1;
}
if (thisCodePoint > otherCodePoint) {
return 1;
}
}
if (thisLength < otherLength) return -1;
if (thisLength > otherLength) return 1;
return 0;
}
bool substringMatches(int start, String other) {
if (other.isEmpty()) return true;
if ((start < 0) || (start >= this.length)) {
return false;
}
final int len = other.length;
if ((start + len) > this.length) {
return false;
}
for (int i = 0; i < len; i++) {
if (this.charCodeAt(i + start) != other.charCodeAt(i)) {
return false;
}
}
return true;
}
bool endsWith(String other) {
return this.substringMatches(this.length - other.length, other);
}
bool startsWith(String other) {
return this.substringMatches(0, other);
}
int indexOf(String other, int startIndex) {
if (other.isEmpty()) {
return startIndex < this.length ? startIndex : this.length;
}
if ((startIndex < 0) || (startIndex >= this.length)) {
return -1;
}
int len = this.length - other.length + 1;
for (int index = startIndex; index < len; index++) {
if (this.substringMatches(index, other)) {
return index;
}
}
return -1;
}
int lastIndexOf(String other, int fromIndex) {
if (other.isEmpty()) {
return Math.min(this.length, fromIndex);
}
if (fromIndex >= this.length) {
fromIndex = this.length - 1;
}
for (int index = fromIndex; index >= 0; index--) {
if (this.substringMatches(index, other)) {
return index;
}
}
return -1;
}
String substring(int startIndex, int endIndex) {
if ((startIndex < 0) || (startIndex > this.length)) {
throw new IndexOutOfRangeException(startIndex);
}
if ((endIndex < 0) || (endIndex > this.length)) {
throw new IndexOutOfRangeException(endIndex);
}
if (startIndex > endIndex) {
throw new IndexOutOfRangeException(startIndex);
}
return substringUnchecked_(startIndex, endIndex);
}
// TODO(terry): Temporary workaround until substring can support a default
// argument for endIndex (when the VM supports default args).
// This method is a place holder to flag breakage for apps
// that depend on this behavior of substring.
String substringToEnd(int startIndex) {
return this.substring(startIndex, this.length);
}
String substringUnchecked_(int startIndex, int endIndex) {
int len = endIndex - startIndex;
Array<int> charCodes = new Array<int>(len);
for (int i = 0; i < len; i++) {
charCodes[i] = this.charCodeAt(startIndex + i);
}
return StringBase.createFromCharCodes(charCodes);
}
String trim() {
int len = this.length;
int first = 0;
for (; first < len; first++) {
if (!_isWhitespace(this.charCodeAt(first))) {
break;
}
}
if (len == first) {
// String contains only whitespaces.
return "";
}
int last = len - 1;
for (int i = last; last >= first; last--) {
if (!_isWhitespace(this.charCodeAt(last))) {
break;
}
}
return substringUnchecked_(first, last + 1);
}
bool contains(Pattern other, int startIndex) {
if (other is RegExp) {
throw "Unimplemented String.contains with RegExp";
}
return indexOf(other, startIndex) >= 0;
}
String replaceFirst(Pattern from, String to) {
if (from is RegExp) {
throw "Unimplemented String.replace with RegExp";
}
int pos = this.indexOf(from, 0);
if (pos < 0) {
return this;
}
String s1 = this.substring(0, pos);
String s2 = this.substring(pos + from.length, this.length);
return s1.concat(to.concat(s2));
}
String replaceAll(Pattern from_, String to) {
if (from_ is RegExp) {
throw "Unimplemented String.replaceAll with RegExp";
}
String from = from_;
int fromLength = from.length;
int toLength = to.length;
int thisLength = this.length;
StringBuffer result = new StringBuffer("");
// Special case the empty string replacement where [to] is
// inserted in between each character.
if (fromLength === 0) {
result.add(to);
for (int i = 0; i < thisLength; i++) {
result.add(this.substring(i, i + 1));
result.add(to);
}
return result.toString();
}
int index = indexOf(from, 0);
if (index < 0) {
return this;
}
int startIndex = 0;
do {
result.add(this.substring(startIndex, index));
result.add(to);
startIndex = index + fromLength;
} while ((index = indexOf(from, startIndex)) >= 0);
// If there are remaining code points, add them to the string
// buffer.
if (startIndex < thisLength) {
result.add(this.substring(startIndex, thisLength));
}
return result.toString();
}
/**
* Convert argument obj to string and concat it with this string.
* Returns concatenated string.
*/
String operator +(Object obj) {
return this.concat(obj.toString());
}
/**
* Convert all objects in [values] to strings and concat them
* into a result string.
*/
static String _interpolate(Array values) {
int numValues = values.length;
Array<String> stringArray = new Array<String>(numValues);
int resultLength = 0;
for (int i = 0; i < numValues; i++) {
String str = values[i].toString();
resultLength += str.length;
stringArray[i] = str;
}
Array<int> codepoints = new Array<int>(resultLength);
int intArrayIx = 0;
for (int i = 0; i < numValues; i++) {
String str = stringArray[i];
int strLength = str.length;
for (int k = 0; k < strLength; k++) {
codepoints[intArrayIx++] = str.charCodeAt(k);
}
}
return StringBase.createFromCharCodes(codepoints);
}
Iterable<Match> allMatches(String str) {
GrowableObjectArray<Match> result = new GrowableObjectArray<Match>();
if (this.isEmpty()) return result;
int length = this.length;
int ix = 0;
while (ix < str.length) {
int foundIx = str.indexOf(this, ix);
if (foundIx < 0) break;
result.add(new _StringMatch(foundIx, str, this));
ix = foundIx + length;
}
return result;
}
Array<String> split(Pattern pattern) {
if (pattern is RegExp) {
throw "Unimplemented split with RegExp";
}
GrowableObjectArray<String> result = new GrowableObjectArray<String>();
if (pattern.isEmpty()) {
for (int i = 0; i < this.length; i++) {
result.add(this.substring(i, i+1));
}
return result;
}
int ix = 0;
while (ix < this.length) {
int foundIx = this.indexOf(pattern, ix);
if (foundIx < 0) {
// Not found, add remaining.
result.add(this.substring(ix, this.length));
break;
}
result.add(this.substring(ix, foundIx));
ix = foundIx + pattern.length;
}
if (ix == this.length) {
result.add("");
}
return result;
}
Array<String> splitChars() {
int len = this.length;
final result = new Array<String>(len);
for (int i = 0; i < len; i++) {
result[i] = this[i];
}
return result;
}
Array<int> charCodes() {
int len = this.length;
final result = new Array<int>(len);
for (int i = 0; i < len; i++) {
result[i] = this.charCodeAt(i);
}
return result;
}
String toLowerCase() {
final int aCode = "A".charCodeAt(0);
final int zCode = "Z".charCodeAt(0);
final int delta = aCode - "a".charCodeAt(0);
return _convert(this, aCode, zCode, delta);
}
String toUpperCase() {
final int aCode = "a".charCodeAt(0);
final int zCode = "z".charCodeAt(0);
final int delta = aCode - "A".charCodeAt(0);
return _convert(this, aCode, zCode, delta);
}
static String _convert(String str, int startCode, int endCode, int delta) {
final int len = str.length;
int i = 0;
// Check if we can just return the string.
for (; i < len; i++) {
int code = str.charCodeAt(i);
if ((startCode <= code) && (code <= endCode)) break;
}
if (i == len) return str;
Array<int> charCodes = new Array<int>(len);
for (i = 0; i < len; i++) {
int code = str.charCodeAt(i);
if ((startCode <= code) && (code <= endCode)) {
code = code - delta;
}
charCodes[i] = code;
}
return StringBase.createFromCharCodes(charCodes);
}
// Implementations of Strings methods follow below.
static String join(Array<String> strings, String separator) {
final int length = strings.length;
if (length === 0) {
return "";
}
Array strings_array = strings;
if (separator.length != 0) {
strings_array = new Array(2 * length - 1);
strings_array[0] = strings[0];
int j = 1;
for (int i = 1; i < length; i++) {
strings_array[j++] = separator;
strings_array[j++] = strings[i];
}
}
return concatAll(strings_array);
}
static String concatAll(Array<String> strings) {
ObjectArray strings_array;
if (strings is ObjectArray) {
strings_array = strings;
} else {
int len = strings.length;
strings_array = new Array(len);
for (int i = 0; i < len; i++) {
strings_array[i] = strings[i];
}
}
return _concatAll(strings_array);
}
static String _concatAll(ObjectArray<String> strings)
native "Strings_concatAll";
}
class OneByteString extends StringBase implements String {
// Checks for one-byte whitespaces only.
// TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid
// whitespaces for one byte strings.
bool _isWhitespace(int codePoint) {
return
(codePoint === 32) || // Space.
((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc.
}
}
class TwoByteString extends StringBase implements String {
// Checks for one-byte whitespaces only.
// TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid
// whitespaces. Add checking for multi-byte whitespace codepoints.
bool _isWhitespace(int codePoint) {
return
(codePoint === 32) || // Space.
((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc.
}
}
class FourByteString extends StringBase implements String {
// Checks for one-byte whitespaces only.
// TODO(srdjan): Investigate if 0x85 (NEL) and 0xA0 (NBSP) are valid
// whitespaces. Add checking for multi-byte whitespace codepoints.
bool _isWhitespace(int codePoint) {
return
(codePoint === 32) || // Space.
((9 <= codePoint) && (codePoint <= 13)); // CR, LF, TAB, etc.
}
}
class _StringMatch implements Match {
const _StringMatch(int this._start,
String this.str,
String this.pattern);
int start() => _start;
int end() => _start + pattern.length;
String operator[](int g) => group(g);
int groupCount() => 0;
String group(int group) {
if (group != 0) {
throw new IndexOutOfRangeException(group);
}
return pattern;
}
Array<String> groups(Array<int> groups) {
Array<String> result = new Array<String>();
for (int g in groups) {
result.add(group(g));
}
return result;
}
final int _start;
final String str;
final String pattern;
}

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