Initial import of Cobalt 2.8885 2016-07-27
diff --git a/src/.clang-format b/src/.clang-format
new file mode 100644
index 0000000..d5c7b08
--- /dev/null
+++ b/src/.clang-format
@@ -0,0 +1,3 @@
+# Defines the Chromium style for automatic reformatting.
+# http://clang.llvm.org/docs/ClangFormatStyleOptions.html
+BasedOnStyle: Chromium
diff --git a/src/AUTHORS b/src/AUTHORS
new file mode 100644
index 0000000..5a7ed82
--- /dev/null
+++ b/src/AUTHORS
@@ -0,0 +1,12 @@
+# Names should be added to this file with this pattern:
+#
+# For individuals:
+# Name <email address>
+#
+# For organizations:
+# Organization <fnmatch pattern>
+#
+# See python fnmatch module documentation for more information.
+
+The Chromium Authors <*@chromium.org>
+Google Inc. <*@google.com>
diff --git a/src/LICENSE b/src/LICENSE
new file mode 100644
index 0000000..3d0f7d3
--- /dev/null
+++ b/src/LICENSE
@@ -0,0 +1,27 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/README.cobalt.txt b/src/README.cobalt.txt
new file mode 100644
index 0000000..bc2d9c7
--- /dev/null
+++ b/src/README.cobalt.txt
@@ -0,0 +1,2 @@
+This is a fork of the chromium repository at http://git.chromium.org/git/chromium.git
+
diff --git a/src/README.md b/src/README.md
new file mode 100644
index 0000000..2d2efba
--- /dev/null
+++ b/src/README.md
@@ -0,0 +1,247 @@
+# Cobalt
+
+## Overview
+
+Cobalt is a lightweight application container (i.e. an application runtime, like
+a JVM or the Flash Player) that is compatible with a subset of the W3C HTML5
+specifications. If you author a single-page web application (SPA) that complies
+with the Cobalt Subset of W3C standards, it will run as well as possible on all
+the devices that Cobalt supports.
+
+
+## Motivation
+
+The Cobalt Authors originally maintained a port of Chromium called H5VCC, the
+HTML5 Video Container for Consoles, ported to each of the major game consoles,
+designed to run our HTML5-based video browse and play application. This took a
+long time to port to each platform, consisted of 9 million lines of C++ code
+(before we touched it), was dangerous to modify without unintended consequences,
+and was thoroughly designed for a resource-rich, multi-process environment
+(e.g. a desktop, laptop, or modern smartphone).
+
+After wrestling with this for several years, we imagined an environment that was
+not designed for traditional scrolling web content, but was intended to be a
+runtime environment for rich client applications built with the same
+technologies -- HTML, CSS, JavaScript -- and designed from the ground-up to run
+on constrained, embedded, Living Room Consumer Electronics (CE) devices, such as
+Game Consoles, Set-Top Boxes (e.g. Cable, Satellite), OTT devices (e.g. Roku,
+Apple TV, Chromecast, Fire TV), Blu-ray Disc Players, and Smart TVs.
+
+These constraints (not intended to be a canonical list) make this device
+spectrum vastly different from the desktop computer environment targeted by
+Chromium, FireFox, and IE:
+
+ * **Limited Memory.** All except the very latest, expensive CE devices have a
+ very small amount of memory available for applications. This usually is
+ somewhere in the ballpark of 200MB-500MB, including graphics and media
+ memory, as opposed to multiple gigabytes of CPU memory (and more gigabytes
+ of GPU memory) in modern desktop and laptop computers, and mobile devices.
+ * **Slow CPUs.** Most CE devices have much slower CPUs than what is available
+ on even a budget desktop computer. Minor performance concerns can be greatly
+ exaggerated, which seriously affects priorities.
+ * **Fewer cores.** CE System-on-a-Chip (SoC) processors often do not have as
+ many processor cores as we are used to in modern computers. Many deployed
+ devices still only have a single core.
+ * **Sometimes No GPU.** Not all CE devices have a monster GPU to throw shaders
+ at to offload CPU work. A different strategy is required to maximize
+ leverage of an accelerated blitter, which is all some older devices
+ have. Some newer CE devices have a GPU, but it's not nearly as powerful as
+ what one would even see on a laptop.
+ * **Sometimes No JIT.** Many CE devices are dealing with "High-Value Content,"
+ and, as such, are very sensitive to security concerns. Ensuring that
+ writable pages are not executable is a strong security protocol that can
+ prevent a wide spectrum of attacks. But, as a side effect, this also means
+ no ability to JIT.
+ * **Heterogenous Development Environments.** This is slowly evening out, but
+ all CE devices run on custom hardware, often with proprietary methods of
+ building, packaging, deploying, and running programs. Almost all CE devices
+ have ARM or MIPS processors instead of the more familiar x86. Sometimes the
+ toolchain doesn't support contemporary C++11 features. Sometimes the OS
+ isn't POSIX, or it tries to be, but it is only partially implemented.
+ Sometimes the program entry point is in another language or architecture
+ that requires a "trampoline" over to native binary code.
+ * **No navigation.** The point of a Single-Page Application is that you don't
+ go through the HTTP page dance every time you switch screens. It's slow, and
+ provides poor user feedback, not to mention a jarring transition. Instead,
+ one loads data from an XMLHttpRequest (XHR), and then updates one's DOM to
+ reflect the new data. AJAX! Web 2.0!!
+ * **No scrolling.** Well, full-screen, 10-foot UI SPA apps might scroll, but
+ not like traditional web pages, with scroll bars and a mouse
+ wheel. Scrolling is generally built into the app very carefully, with
+ support for a Directional Pad and a focus cursor.
+
+
+## Architecture
+
+The Cobalt Authors forked H5VCC, removed most of the Chromium code -- in
+particular WebCore and the Chrome Renderer and Compositor -- and built up from
+scratch an implementation of a simplified subset of HTML, the CSS Box Model for
+layout, and the Web APIs that were really needed to build a full-screen SPA
+browse and play application.
+
+The Cobalt technology stack has these major components, roughly in a high-level
+application to a low-level platform order:
+
+ * **Web Implementation** - This is where the W3C standards are implemented,
+ ultimately producing an annotated DOM tree that can be passed into the
+ Layout Engine to produce a Render Tree.
+ * **JavaScript Engine** - We have, perhaps surprisingly, *not* written our own
+ JavaScript Engine from scratch. Because of the JITing constraint, we have to
+ be flexible with which engine(s) we work with. We have a bindings layer that
+ interfaces with the JS Engine so that application script can interface with
+ natively-backed objects (like DOM elements).
+ * **Layout Engine** - The Layout Engine takes an annotated DOM Document
+ produced by the Web Implementation and JavaScript Engine working together,
+ and calculates a tree of rendering commands to send to the renderer (i.e. a
+ Render Tree). It caches intermediate layout artifacts so that subsequent
+ incremental layouts can be sped up.
+ * **Renderer/Skia** - The Renderer walks a Render Tree produced by the Layout
+ Engine, rasterizes it using the third-party graphics library Skia, and swaps
+ it to the front buffer. There are two major paths here, one using Hardware
+ Skia on OpenGL ES 2.0, and one using Software Skia combined with the
+ hardware-accelerated Starboard Blitter. Note that the renderer runs in a
+ different thread from the Layout Engine, and can interpolate animations that
+ do not require re-layout. This decouples rendering from Layout and
+ JavaScript, allowing for smooth, consistent animations on platforms with a
+ variety of capabilities.
+ * **Net / Media** - These are Chromium's Network and Media engines. We are
+ using them directly, as they don't cause any particular problems with the
+ extra constraints listed above.
+ * **Base** - This is Chromium's "Base" library, which contains a wide variety
+ of useful things used throughout Cobalt, Net, and Media. Cobalt uses a
+ combination of standard C++ containers (e.g. vector, string) and Base as the
+ foundation library for all of its code.
+ * **Other Third-party Libraries** - Most of these are venerable, straight-C,
+ open-source libraries that are commonly included in other open-source
+ software. Mostly format decoders and parsers (e.g. libpng, libxml2,
+ zlib). We fork these from Chromium, as we want them to be the most
+ battle-tested versions of these libraries.
+ * **Starboard/Glimp/ANGLE** - **Starboard** is the Cobalt porting
+ interface. One major difference between Cobalt and Chromium is that we have
+ created a hard straight-C porting layer, and ported ALL of the compiled
+ code, including Base and all third-party libraries, to use it instead of
+ directly using POSIX standard libraries, which are not consistent, even on
+ modern systems (see Android, Windows, MacOS X, and iOS). Additionally,
+ Starboard includes APIs that haven't been effectively standardized across
+ platforms, such as display Window creation, Input events, and Media
+ playback. **Glimp** is an OpenGL ES 2.0 implementation framework, built by
+ the Cobalt team directly on Starboard, designed to adapt proprietary 3D APIs
+ to GLES2. **ANGLE** Is a third-party library that adapts DirectX to GLES2,
+ similar to Glimp, but only for DirectX.
+
+Cobalt is like a flaky layered pastry - perhaps Baklava. It shouldn't be too
+difficult to rip the Web Implementation and Layout off the top, and just use the
+Renderer, or even to just use Base + Starboard + GLES2 as the basis of a new
+project.
+
+
+## The Cobalt Subset
+
+> Oh, we got both kinds of HTML tags,\
+> we got `<span>` and `<div>`!
+
+See the [Cobalt Subset specification](TODO) for more details on which tags,
+properties, and Web APIs are supported in Cobalt.
+
+*More to come.*
+
+
+## Interesting Source Locations
+
+All source locations are specified relative to `src/` (this directory).
+
+ * `base/` - Chromium's Base library. Contains common utilities, and a light
+ platform abstraction, which has been superceded in Cobalt by Starboard.
+ * `net/` - Chromium's Network library. Contains enough infrastructure to
+ support the network needs of an HTTP User-Agent (like Chromium or Cobalt),
+ an HTTP server, a DIAL server, and several abstractions for networking
+ primitives. Also contains SPDY and QUIC implementations.
+ * `media/` - Chromium's Media library. Contains all the code that parses,
+ processes, and manages buffers of video and audio data. Media decoding is
+ passed off to decoding hardware, wherever possible.
+ * `cobalt/` - The home of all Cobalt application code. This includes the Web
+ Implementation, Layout Engine, Renderer, and some other Cobalt-specific
+ features.
+ * `cobalt/build/` - The core build generation system, `gyp_cobalt`, and
+ configurations for supported platforms. (NOTE: This should eventually be
+ mostly moved into `starboard/`.)
+ * `starboard/` - Cobalt's porting layer. Please see Starboard's
+ [`README.md`](starboard/README.md) for more detailed information about
+ porting Starboard (and Cobalt) to a new platform.
+ * `third_party/` - Where all of Cobalt's third-party dependencies live. We
+ don't mean to be perjorative, we love our third-party libraries! This
+ location is dictated by Google OSS release management rules...
+ * `third_party/starboard/` - The location for third-party ports. This
+ directory will be scanned automatically by gyp_cobalt for available
+ Starboard ports.
+
+
+## Building and Running the Code
+
+Here's a quick and dirty guide to get to build the code on Linux.
+
+ 1. Install the provided `depot_tools` archive into your favorite directory. It
+ has been slightly modified from Chromium's `depot_tools`.
+ 2. Add that directory to the end of your `$PATH`.
+ 3. Ensure you have these packages installed: `sudo apt-get install
+ libgles2-mesa-dev libpulse-dev libavformat-dev libavresample-dev
+ libasound2-dev libxrender-dev libxcomposite-dev`
+ 4. Ensure you have the standard C++ header files installed
+ (e.g. `libstdc++-4.8-dev`).
+ 5. Remove bison-3 and install bison-2.7, or just make sure that bison-2.7 is
+ before bison-3 on your `$PATH`. (NOTE: We plan on moving to bison-3 in the
+ future.)
+
+ $ sudo apt-get remove bison
+ $ sudo apt-get install m4
+ $ wget http://ftp.gnu.org/gnu/bison/bison-2.7.1.tar.gz
+ $ tar zxf bison-2.7.1.tar.gz
+ $ cd bison-2.7.1
+ $ sh configure && make && sudo make install
+ $ which bison
+ /usr/local/bin/bison
+ $ bison --version
+ bison (GNU Bison) 2.7.12-4996
+
+ 6. (From this directory) run GYP:
+
+ cobalt/build/gyp_cobalt -C debug linux-x64x11
+
+ 7. If you get a "clang not found" error, add the path to Cobalt's clang to
+ your `$PATH` and rerun `gyp_cobalt` as above. For example:
+ `/path/to/cobalt/src/third_party/llvm-build/Release+Asserts/bin`
+ 8. Run Ninja:
+
+ ninja -C out/linux-x64x11_debug cobalt
+
+ 9. Run Cobalt:
+
+ out/linux-x64x11_debug/cobalt [--url=<url>]
+
+ * If you want to use `http` instead of `https`, you must pass the
+ `--allow_http` flag to the Cobalt command-line.
+ * If you want to connect to an `https` host that doesn't have a
+ globally-validatable certificate, you must pass the
+ `--ignore_certificate_errors` flag to the Cobalt command-line.
+ * See `cobalt/browser/switches.cc` for more command-line options.
+
+
+## Build Types
+
+Cobalt has four build optimization levels, going from the slowest, least
+optimized, with the most debug information at the top (debug) to the fastest,
+most optimized, and with the least debug information at the bottom (gold):
+
+ | Type | Optimizations | Logging | Asserts | Debug Info | Console |
+ | :---- | :------------ | :------ | :------ | :--------- | :------- |
+ | debug | None | Full | Full | Full | Enabled |
+ | devel | Full | Full | Full | Full | Enabled |
+ | qa | Full | Limited | None | None | Enabled |
+ | gold | Full | None | None | None | Disabled |
+
+When building for release, you should always use a gold build for the final
+product.
+
+ $ cobalt/build/gyp_cobalt -C gold linux-x64x11
+ $ ninja -C out/linux-x64x11_gold cobalt
+ $ out/linux-x64x11_gold/cobalt
diff --git a/src/base/allocator/README b/src/base/allocator/README
new file mode 100644
index 0000000..ec8a707
--- /dev/null
+++ b/src/base/allocator/README
@@ -0,0 +1,59 @@
+Notes about the Chrome memory allocator.
+
+Background
+----------
+We use this library as a generic way to fork into any of several allocators.
+Currently we can, at runtime, switch between:
+ the default windows allocator
+ the windows low-fragmentation-heap
+ tcmalloc
+ jemalloc (the heap used most notably within Mozilla Firefox)
+
+The mechanism for hooking LIBCMT in windows is rather tricky. The core
+problem is that by default, the windows library does not declare malloc and
+free as weak symbols. Because of this, they cannot be overriden. To work
+around this, we start with the LIBCMT.LIB, and manually remove all allocator
+related functions from it using the visual studio library tool. Once removed,
+we can now link against the library and provide custom versions of the
+allocator related functionality.
+
+
+Source code
+-----------
+This directory contains just the allocator (i.e. shim) layer that switches
+between the different underlying memory allocation implementations.
+
+The tcmalloc and jemalloc libraries originate outside of Chromium
+and exist in ../../third_party/tcmalloc and ../../third_party/jemalloc
+(currently, the actual locations are defined in the allocator.gyp file).
+The third party sources use a vendor-branch SCM pattern to track
+Chromium-specific changes independently from upstream changes.
+
+The general intent is to push local changes upstream so that over
+time we no longer need any forked files.
+
+
+Adding a new allocator
+----------------------
+Adding a new allocator requires definition of the following five functions:
+
+ extern "C" {
+ bool init();
+ void* malloc(size_t s);
+ void* realloc(void* p, size_t s);
+ void free(void* s);
+ size_t msize(void* p);
+ }
+
+All other allocation related functions (new/delete/calloc/etc) have been
+implemented generically to work across all allocators.
+
+
+Usage
+-----
+You can use the different allocators by setting the environment variable
+CHROME_ALLOCATOR to:
+ "tcmalloc" - TC Malloc (default)
+ "jemalloc" - JE Malloc
+ "winheap" - Windows default heap
+ "winlfh" - Windows Low-Fragmentation heap
diff --git a/src/base/allocator/allocator.gyp b/src/base/allocator/allocator.gyp
new file mode 100644
index 0000000..f5bda73
--- /dev/null
+++ b/src/base/allocator/allocator.gyp
@@ -0,0 +1,671 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'jemalloc_dir': '../../third_party/jemalloc/chromium',
+ 'tcmalloc_dir': '../../third_party/tcmalloc/chromium',
+ 'use_vtable_verify%': 0,
+ },
+ 'targets': [
+ # Only executables and not libraries should depend on the
+ # allocator target; only the application (the final executable)
+ # knows what allocator makes sense.
+ {
+ 'target_name': 'allocator',
+ 'type': 'static_library',
+ # Make sure the allocation library is optimized to
+ # the hilt in official builds.
+ 'variables': {
+ 'optimize': 'max',
+ },
+ 'include_dirs': [
+ '.',
+ '<(tcmalloc_dir)/src/base',
+ '<(tcmalloc_dir)/src',
+ '../..',
+ ],
+ 'direct_dependent_settings': {
+ 'configurations': {
+ 'Common_Base': {
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'IgnoreDefaultLibraryNames': ['libcmtd.lib', 'libcmt.lib'],
+ 'AdditionalDependencies': [
+ '<(SHARED_INTERMEDIATE_DIR)/allocator/libcmt.lib'
+ ],
+ },
+ },
+ },
+ },
+ 'conditions': [
+ ['OS=="win"', {
+ 'defines': [
+ 'PERFTOOLS_DLL_DECL=',
+ ],
+ }],
+ ],
+ },
+ 'sources': [
+ # Generated for our configuration from tcmalloc's build
+ # and checked in.
+ '<(tcmalloc_dir)/src/config.h',
+ '<(tcmalloc_dir)/src/config_linux.h',
+ '<(tcmalloc_dir)/src/config_win.h',
+
+ # all tcmalloc native and forked files
+ '<(tcmalloc_dir)/src/addressmap-inl.h',
+ '<(tcmalloc_dir)/src/base/abort.cc',
+ '<(tcmalloc_dir)/src/base/abort.h',
+ '<(tcmalloc_dir)/src/base/arm_instruction_set_select.h',
+ '<(tcmalloc_dir)/src/base/atomicops-internals-linuxppc.h',
+ '<(tcmalloc_dir)/src/base/atomicops-internals-arm-generic.h',
+ '<(tcmalloc_dir)/src/base/atomicops-internals-arm-v6plus.h',
+ '<(tcmalloc_dir)/src/base/atomicops-internals-macosx.h',
+ '<(tcmalloc_dir)/src/base/atomicops-internals-windows.h',
+ '<(tcmalloc_dir)/src/base/atomicops-internals-x86.cc',
+ '<(tcmalloc_dir)/src/base/atomicops-internals-x86.h',
+ '<(tcmalloc_dir)/src/base/atomicops.h',
+ '<(tcmalloc_dir)/src/base/basictypes.h',
+ '<(tcmalloc_dir)/src/base/commandlineflags.h',
+ '<(tcmalloc_dir)/src/base/cycleclock.h',
+ # We don't list dynamic_annotations.c since its copy is already
+ # present in the dynamic_annotations target.
+ '<(tcmalloc_dir)/src/base/dynamic_annotations.h',
+ '<(tcmalloc_dir)/src/base/elf_mem_image.cc',
+ '<(tcmalloc_dir)/src/base/elf_mem_image.h',
+ '<(tcmalloc_dir)/src/base/elfcore.h',
+ '<(tcmalloc_dir)/src/base/googleinit.h',
+ '<(tcmalloc_dir)/src/base/linux_syscall_support.h',
+ '<(tcmalloc_dir)/src/base/linuxthreads.cc',
+ '<(tcmalloc_dir)/src/base/linuxthreads.h',
+ '<(tcmalloc_dir)/src/base/logging.cc',
+ '<(tcmalloc_dir)/src/base/logging.h',
+ '<(tcmalloc_dir)/src/base/low_level_alloc.cc',
+ '<(tcmalloc_dir)/src/base/low_level_alloc.h',
+ '<(tcmalloc_dir)/src/base/simple_mutex.h',
+ '<(tcmalloc_dir)/src/base/spinlock.cc',
+ '<(tcmalloc_dir)/src/base/spinlock.h',
+ '<(tcmalloc_dir)/src/base/spinlock_internal.cc',
+ '<(tcmalloc_dir)/src/base/spinlock_internal.h',
+ '<(tcmalloc_dir)/src/base/spinlock_linux-inl.h',
+ '<(tcmalloc_dir)/src/base/spinlock_posix-inl.h',
+ '<(tcmalloc_dir)/src/base/spinlock_win32-inl.h',
+ '<(tcmalloc_dir)/src/base/stl_allocator.h',
+ '<(tcmalloc_dir)/src/base/synchronization_profiling.h',
+ '<(tcmalloc_dir)/src/base/sysinfo.cc',
+ '<(tcmalloc_dir)/src/base/sysinfo.h',
+ '<(tcmalloc_dir)/src/base/thread_annotations.h',
+ '<(tcmalloc_dir)/src/base/thread_lister.c',
+ '<(tcmalloc_dir)/src/base/thread_lister.h',
+ '<(tcmalloc_dir)/src/base/vdso_support.cc',
+ '<(tcmalloc_dir)/src/base/vdso_support.h',
+ '<(tcmalloc_dir)/src/central_freelist.cc',
+ '<(tcmalloc_dir)/src/central_freelist.h',
+ '<(tcmalloc_dir)/src/common.cc',
+ '<(tcmalloc_dir)/src/common.h',
+ '<(tcmalloc_dir)/src/debugallocation.cc',
+ '<(tcmalloc_dir)/src/deep-heap-profile.cc',
+ '<(tcmalloc_dir)/src/deep-heap-profile.h',
+ '<(tcmalloc_dir)/src/free_list.cc',
+ '<(tcmalloc_dir)/src/free_list.h',
+ '<(tcmalloc_dir)/src/getpc.h',
+ '<(tcmalloc_dir)/src/gperftools/heap-checker.h',
+ '<(tcmalloc_dir)/src/gperftools/heap-profiler.h',
+ '<(tcmalloc_dir)/src/gperftools/malloc_extension.h',
+ '<(tcmalloc_dir)/src/gperftools/malloc_extension_c.h',
+ '<(tcmalloc_dir)/src/gperftools/malloc_hook.h',
+ '<(tcmalloc_dir)/src/gperftools/malloc_hook_c.h',
+ '<(tcmalloc_dir)/src/gperftools/profiler.h',
+ '<(tcmalloc_dir)/src/gperftools/stacktrace.h',
+ '<(tcmalloc_dir)/src/gperftools/tcmalloc.h',
+ '<(tcmalloc_dir)/src/heap-checker-bcad.cc',
+ '<(tcmalloc_dir)/src/heap-checker.cc',
+ '<(tcmalloc_dir)/src/heap-profile-table.cc',
+ '<(tcmalloc_dir)/src/heap-profile-table.h',
+ '<(tcmalloc_dir)/src/heap-profiler.cc',
+ '<(tcmalloc_dir)/src/internal_logging.cc',
+ '<(tcmalloc_dir)/src/internal_logging.h',
+ '<(tcmalloc_dir)/src/libc_override.h',
+ '<(tcmalloc_dir)/src/libc_override_gcc_and_weak.h',
+ '<(tcmalloc_dir)/src/libc_override_glibc.h',
+ '<(tcmalloc_dir)/src/libc_override_osx.h',
+ '<(tcmalloc_dir)/src/libc_override_redefine.h',
+ '<(tcmalloc_dir)/src/linked_list.h',
+ '<(tcmalloc_dir)/src/malloc_extension.cc',
+ '<(tcmalloc_dir)/src/malloc_hook-inl.h',
+ '<(tcmalloc_dir)/src/malloc_hook.cc',
+ '<(tcmalloc_dir)/src/malloc_hook_mmap_freebsd.h',
+ '<(tcmalloc_dir)/src/malloc_hook_mmap_linux.h',
+ '<(tcmalloc_dir)/src/maybe_threads.cc',
+ '<(tcmalloc_dir)/src/maybe_threads.h',
+ '<(tcmalloc_dir)/src/memfs_malloc.cc',
+ '<(tcmalloc_dir)/src/memory_region_map.cc',
+ '<(tcmalloc_dir)/src/memory_region_map.h',
+ '<(tcmalloc_dir)/src/packed-cache-inl.h',
+ '<(tcmalloc_dir)/src/page_heap.cc',
+ '<(tcmalloc_dir)/src/page_heap.h',
+ '<(tcmalloc_dir)/src/page_heap_allocator.h',
+ '<(tcmalloc_dir)/src/pagemap.h',
+ '<(tcmalloc_dir)/src/profile-handler.cc',
+ '<(tcmalloc_dir)/src/profile-handler.h',
+ '<(tcmalloc_dir)/src/profiledata.cc',
+ '<(tcmalloc_dir)/src/profiledata.h',
+ '<(tcmalloc_dir)/src/profiler.cc',
+ '<(tcmalloc_dir)/src/raw_printer.cc',
+ '<(tcmalloc_dir)/src/raw_printer.h',
+ '<(tcmalloc_dir)/src/sampler.cc',
+ '<(tcmalloc_dir)/src/sampler.h',
+ '<(tcmalloc_dir)/src/span.cc',
+ '<(tcmalloc_dir)/src/span.h',
+ '<(tcmalloc_dir)/src/stack_trace_table.cc',
+ '<(tcmalloc_dir)/src/stack_trace_table.h',
+ '<(tcmalloc_dir)/src/stacktrace.cc',
+ '<(tcmalloc_dir)/src/stacktrace_arm-inl.h',
+ '<(tcmalloc_dir)/src/stacktrace_config.h',
+ '<(tcmalloc_dir)/src/stacktrace_generic-inl.h',
+ '<(tcmalloc_dir)/src/stacktrace_libunwind-inl.h',
+ '<(tcmalloc_dir)/src/stacktrace_powerpc-inl.h',
+ '<(tcmalloc_dir)/src/stacktrace_win32-inl.h',
+ '<(tcmalloc_dir)/src/stacktrace_with_context.cc',
+ '<(tcmalloc_dir)/src/stacktrace_x86-inl.h',
+ '<(tcmalloc_dir)/src/static_vars.cc',
+ '<(tcmalloc_dir)/src/static_vars.h',
+ '<(tcmalloc_dir)/src/symbolize.cc',
+ '<(tcmalloc_dir)/src/symbolize.h',
+ '<(tcmalloc_dir)/src/system-alloc.cc',
+ '<(tcmalloc_dir)/src/system-alloc.h',
+ '<(tcmalloc_dir)/src/tcmalloc.cc',
+ '<(tcmalloc_dir)/src/tcmalloc_guard.h',
+ '<(tcmalloc_dir)/src/thread_cache.cc',
+ '<(tcmalloc_dir)/src/thread_cache.h',
+ '<(tcmalloc_dir)/src/windows/config.h',
+ '<(tcmalloc_dir)/src/windows/get_mangled_names.cc',
+ '<(tcmalloc_dir)/src/windows/gperftools/tcmalloc.h',
+ '<(tcmalloc_dir)/src/windows/ia32_modrm_map.cc',
+ '<(tcmalloc_dir)/src/windows/ia32_opcode_map.cc',
+ '<(tcmalloc_dir)/src/windows/mingw.h',
+ '<(tcmalloc_dir)/src/windows/mini_disassembler.cc',
+ '<(tcmalloc_dir)/src/windows/mini_disassembler.h',
+ '<(tcmalloc_dir)/src/windows/mini_disassembler_types.h',
+ '<(tcmalloc_dir)/src/windows/override_functions.cc',
+ '<(tcmalloc_dir)/src/windows/patch_functions.cc',
+ '<(tcmalloc_dir)/src/windows/port.cc',
+ '<(tcmalloc_dir)/src/windows/port.h',
+ '<(tcmalloc_dir)/src/windows/preamble_patcher.cc',
+ '<(tcmalloc_dir)/src/windows/preamble_patcher.h',
+ '<(tcmalloc_dir)/src/windows/preamble_patcher_with_stub.cc',
+
+ # jemalloc files
+ '<(jemalloc_dir)/jemalloc.c',
+ '<(jemalloc_dir)/jemalloc.h',
+ '<(jemalloc_dir)/ql.h',
+ '<(jemalloc_dir)/qr.h',
+ '<(jemalloc_dir)/rb.h',
+
+ 'allocator_shim.cc',
+ 'allocator_shim.h',
+ 'debugallocation_shim.cc',
+ 'generic_allocators.cc',
+ 'win_allocator.cc',
+ ],
+ # sources! means that these are not compiled directly.
+ 'sources!': [
+ # Included by allocator_shim.cc for maximal inlining.
+ 'generic_allocators.cc',
+ 'win_allocator.cc',
+
+ # Included by debugallocation_shim.cc.
+ '<(tcmalloc_dir)/src/debugallocation.cc',
+ '<(tcmalloc_dir)/src/tcmalloc.cc',
+
+ # We simply don't use these, but list them above so that IDE
+ # users can view the full available source for reference, etc.
+ '<(tcmalloc_dir)/src/addressmap-inl.h',
+ '<(tcmalloc_dir)/src/base/atomicops-internals-linuxppc.h',
+ '<(tcmalloc_dir)/src/base/atomicops-internals-macosx.h',
+ '<(tcmalloc_dir)/src/base/atomicops-internals-x86-msvc.h',
+ '<(tcmalloc_dir)/src/base/atomicops-internals-x86.cc',
+ '<(tcmalloc_dir)/src/base/atomicops-internals-x86.h',
+ '<(tcmalloc_dir)/src/base/atomicops.h',
+ '<(tcmalloc_dir)/src/base/basictypes.h',
+ '<(tcmalloc_dir)/src/base/commandlineflags.h',
+ '<(tcmalloc_dir)/src/base/cycleclock.h',
+ '<(tcmalloc_dir)/src/base/elf_mem_image.h',
+ '<(tcmalloc_dir)/src/base/elfcore.h',
+ '<(tcmalloc_dir)/src/base/googleinit.h',
+ '<(tcmalloc_dir)/src/base/linux_syscall_support.h',
+ '<(tcmalloc_dir)/src/base/simple_mutex.h',
+ '<(tcmalloc_dir)/src/base/spinlock_linux-inl.h',
+ '<(tcmalloc_dir)/src/base/spinlock_posix-inl.h',
+ '<(tcmalloc_dir)/src/base/spinlock_win32-inl.h',
+ '<(tcmalloc_dir)/src/base/stl_allocator.h',
+ '<(tcmalloc_dir)/src/base/thread_annotations.h',
+ '<(tcmalloc_dir)/src/getpc.h',
+ '<(tcmalloc_dir)/src/gperftools/heap-checker.h',
+ '<(tcmalloc_dir)/src/gperftools/heap-profiler.h',
+ '<(tcmalloc_dir)/src/gperftools/malloc_extension.h',
+ '<(tcmalloc_dir)/src/gperftools/malloc_extension_c.h',
+ '<(tcmalloc_dir)/src/gperftools/malloc_hook.h',
+ '<(tcmalloc_dir)/src/gperftools/malloc_hook_c.h',
+ '<(tcmalloc_dir)/src/gperftools/profiler.h',
+ '<(tcmalloc_dir)/src/gperftools/stacktrace.h',
+ '<(tcmalloc_dir)/src/gperftools/tcmalloc.h',
+ '<(tcmalloc_dir)/src/libc_override.h',
+ '<(tcmalloc_dir)/src/libc_override_gcc_and_weak.h',
+ '<(tcmalloc_dir)/src/libc_override_glibc.h',
+ '<(tcmalloc_dir)/src/libc_override_osx.h',
+ '<(tcmalloc_dir)/src/libc_override_redefine.h',
+ '<(tcmalloc_dir)/src/malloc_hook_mmap_freebsd.h',
+ '<(tcmalloc_dir)/src/malloc_hook_mmap_linux.h',
+ '<(tcmalloc_dir)/src/memfs_malloc.cc',
+ '<(tcmalloc_dir)/src/packed-cache-inl.h',
+ '<(tcmalloc_dir)/src/page_heap_allocator.h',
+ '<(tcmalloc_dir)/src/pagemap.h',
+ '<(tcmalloc_dir)/src/stacktrace_arm-inl.h',
+ '<(tcmalloc_dir)/src/stacktrace_config.h',
+ '<(tcmalloc_dir)/src/stacktrace_generic-inl.h',
+ '<(tcmalloc_dir)/src/stacktrace_libunwind-inl.h',
+ '<(tcmalloc_dir)/src/stacktrace_powerpc-inl.h',
+ '<(tcmalloc_dir)/src/stacktrace_win32-inl.h',
+ '<(tcmalloc_dir)/src/stacktrace_with_context.cc',
+ '<(tcmalloc_dir)/src/stacktrace_x86-inl.h',
+ '<(tcmalloc_dir)/src/tcmalloc_guard.h',
+ '<(tcmalloc_dir)/src/windows/config.h',
+ '<(tcmalloc_dir)/src/windows/gperftools/tcmalloc.h',
+ '<(tcmalloc_dir)/src/windows/get_mangled_names.cc',
+ '<(tcmalloc_dir)/src/windows/ia32_modrm_map.cc',
+ '<(tcmalloc_dir)/src/windows/ia32_opcode_map.cc',
+ '<(tcmalloc_dir)/src/windows/mingw.h',
+ '<(tcmalloc_dir)/src/windows/mini_disassembler.cc',
+ '<(tcmalloc_dir)/src/windows/mini_disassembler.h',
+ '<(tcmalloc_dir)/src/windows/mini_disassembler_types.h',
+ '<(tcmalloc_dir)/src/windows/override_functions.cc',
+ '<(tcmalloc_dir)/src/windows/patch_functions.cc',
+ '<(tcmalloc_dir)/src/windows/preamble_patcher.cc',
+ '<(tcmalloc_dir)/src/windows/preamble_patcher.h',
+ '<(tcmalloc_dir)/src/windows/preamble_patcher_with_stub.cc',
+ ],
+ 'dependencies': [
+ '../third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+ ],
+ 'msvs_settings': {
+ # TODO(sgk): merge this with build/common.gypi settings
+ 'VCLibrarianTool': {
+ 'AdditionalOptions': ['/ignore:4006,4221'],
+ 'AdditionalLibraryDirectories':
+ ['<(DEPTH)/third_party/platformsdk_win7/files/Lib'],
+ },
+ 'VCLinkerTool': {
+ 'AdditionalOptions': ['/ignore:4006'],
+ },
+ },
+ 'configurations': {
+ 'Debug_Base': {
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'RuntimeLibrary': '0',
+ },
+ },
+ 'variables': {
+ # Provide a way to force disable debugallocation in Debug builds,
+ # e.g. for profiling (it's more rare to profile Debug builds,
+ # but people sometimes need to do that).
+ 'disable_debugallocation%': 1,
+ },
+ 'conditions': [
+ ['disable_debugallocation==0', {
+ 'defines': [
+ # Use debugallocation for Debug builds to catch problems early
+ # and cleanly, http://crbug.com/30715 .
+ 'TCMALLOC_FOR_DEBUGALLOCATION',
+ ],
+ }],
+ ],
+ },
+ },
+ 'conditions': [
+ ['OS=="linux" and clang_type_profiler==1', {
+ 'dependencies': [
+ 'type_profiler_tcmalloc',
+ ],
+ # It is undoing dependencies and cflags_cc for type_profiler which
+ # build/common.gypi injects into all targets.
+ 'dependencies!': [
+ 'type_profiler',
+ ],
+ 'cflags_cc!': [
+ '-fintercept-allocation-functions',
+ ],
+ }],
+ ['OS=="win"', {
+ 'defines': [
+ 'PERFTOOLS_DLL_DECL=',
+ ],
+ 'defines!': [
+ # tcmalloc source files unconditionally define this, remove it from
+ # the list of defines that common.gypi defines globally.
+ 'NOMINMAX',
+ ],
+ 'dependencies': [
+ 'libcmt',
+ ],
+ 'include_dirs': [
+ '<(jemalloc_dir)',
+ '<(tcmalloc_dir)/src/windows',
+ ],
+ 'sources!': [
+ '<(tcmalloc_dir)/src/base/elf_mem_image.cc',
+ '<(tcmalloc_dir)/src/base/elf_mem_image.h',
+ '<(tcmalloc_dir)/src/base/linuxthreads.cc',
+ '<(tcmalloc_dir)/src/base/linuxthreads.h',
+ '<(tcmalloc_dir)/src/base/vdso_support.cc',
+ '<(tcmalloc_dir)/src/base/vdso_support.h',
+ '<(tcmalloc_dir)/src/maybe_threads.cc',
+ '<(tcmalloc_dir)/src/maybe_threads.h',
+ '<(tcmalloc_dir)/src/symbolize.h',
+ '<(tcmalloc_dir)/src/system-alloc.cc',
+ '<(tcmalloc_dir)/src/system-alloc.h',
+
+ # included by allocator_shim.cc
+ 'debugallocation_shim.cc',
+
+ # heap-profiler/checker/cpuprofiler
+ '<(tcmalloc_dir)/src/base/thread_lister.c',
+ '<(tcmalloc_dir)/src/base/thread_lister.h',
+ '<(tcmalloc_dir)/src/deep-heap-profile.cc',
+ '<(tcmalloc_dir)/src/deep-heap-profile.h',
+ '<(tcmalloc_dir)/src/heap-checker-bcad.cc',
+ '<(tcmalloc_dir)/src/heap-checker.cc',
+ '<(tcmalloc_dir)/src/heap-profiler.cc',
+ '<(tcmalloc_dir)/src/heap-profile-table.cc',
+ '<(tcmalloc_dir)/src/heap-profile-table.h',
+ '<(tcmalloc_dir)/src/memory_region_map.cc',
+ '<(tcmalloc_dir)/src/memory_region_map.h',
+ '<(tcmalloc_dir)/src/profiledata.cc',
+ '<(tcmalloc_dir)/src/profiledata.h',
+ '<(tcmalloc_dir)/src/profile-handler.cc',
+ '<(tcmalloc_dir)/src/profile-handler.h',
+ '<(tcmalloc_dir)/src/profiler.cc',
+ ],
+ }],
+ ['OS=="linux" or OS=="freebsd" or OS=="solaris"', {
+ 'sources!': [
+ '<(tcmalloc_dir)/src/system-alloc.h',
+ '<(tcmalloc_dir)/src/windows/port.cc',
+ '<(tcmalloc_dir)/src/windows/port.h',
+
+ # TODO(willchan): Support allocator shim later on.
+ 'allocator_shim.cc',
+
+ # TODO(willchan): support jemalloc on other platforms
+ # jemalloc files
+ '<(jemalloc_dir)/jemalloc.c',
+ '<(jemalloc_dir)/jemalloc.h',
+ '<(jemalloc_dir)/ql.h',
+ '<(jemalloc_dir)/qr.h',
+ '<(jemalloc_dir)/rb.h',
+
+ ],
+ # We enable all warnings by default, but upstream disables a few.
+ # Keep "-Wno-*" flags in sync with upstream by comparing against:
+ # http://code.google.com/p/google-perftools/source/browse/trunk/Makefile.am
+ 'cflags': [
+ '-Wno-sign-compare',
+ '-Wno-unused-result',
+ ],
+ 'cflags!': [
+ '-fvisibility=hidden',
+ ],
+ 'link_settings': {
+ 'ldflags': [
+ # Don't let linker rip this symbol out, otherwise the heap&cpu
+ # profilers will not initialize properly on startup.
+ '-Wl,-uIsHeapProfilerRunning,-uProfilerStart',
+ # Do the same for heap leak checker.
+ '-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi',
+ '-Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl',
+ '-Wl,-u_ZN15HeapLeakChecker12IgnoreObjectEPKv,-u_ZN15HeapLeakChecker14UnIgnoreObjectEPKv',
+ ]},
+ }],
+ [ 'use_vtable_verify==1', {
+ 'cflags': [
+ '-fvtable-verify=preinit',
+ ],
+ }],
+ [ 'linux_keep_shadow_stacks==1', {
+ 'sources': [
+ '<(tcmalloc_dir)/src/linux_shadow_stacks.cc',
+ '<(tcmalloc_dir)/src/linux_shadow_stacks.h',
+ '<(tcmalloc_dir)/src/stacktrace_shadow-inl.h',
+ ],
+ 'cflags': [
+ '-finstrument-functions',
+ ],
+ 'defines': [
+ 'KEEP_SHADOW_STACKS',
+ ],
+ }],
+ [ 'linux_use_heapchecker==0', {
+ # Do not compile and link the heapchecker source.
+ 'sources!': [
+ '<(tcmalloc_dir)/src/heap-checker-bcad.cc',
+ '<(tcmalloc_dir)/src/heap-checker.cc',
+ ],
+ # Disable the heap checker in tcmalloc.
+ 'defines': [
+ 'NO_HEAP_CHECK',
+ ],
+ }],
+ [ 'clang==1', {
+ 'cflags': [
+ '-Wno-non-literal-null-conversion',
+ ],
+ }],
+ ['order_profiling != 0', {
+ 'target_conditions' : [
+ ['_toolset=="target"', {
+ 'cflags!': [ '-finstrument-functions' ],
+ }],
+ ],
+ }],
+ ],
+ },
+ {
+ # This library is linked in to src/base.gypi:base and allocator_unittests
+ # It can't depend on either and nothing else should depend on it - all
+ # other code should use the interfaced provided by base.
+ 'target_name': 'allocator_extension_thunks',
+ 'type': 'static_library',
+ 'sources': [
+ 'allocator_extension_thunks.cc',
+ 'allocator_extension_thunks.h',
+ ],
+ 'toolsets': ['host', 'target'],
+ 'include_dirs': [
+ '../../'
+ ],
+ 'conditions': [
+ ['OS=="linux" and clang_type_profiler==1', {
+ # It is undoing dependencies and cflags_cc for type_profiler which
+ # build/common.gypi injects into all targets.
+ 'dependencies!': [
+ 'type_profiler',
+ ],
+ 'cflags_cc!': [
+ '-fintercept-allocation-functions',
+ ],
+ }],
+ ],
+ },
+ ],
+ 'conditions': [
+ ['OS=="win"', {
+ 'targets': [
+ {
+ 'target_name': 'libcmt',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'action_name': 'libcmt',
+ 'inputs': [
+ 'prep_libc.py',
+ ],
+ 'outputs': [
+ '<(SHARED_INTERMEDIATE_DIR)/allocator/libcmt.lib',
+ ],
+ 'action': [
+ 'python',
+ 'prep_libc.py',
+ '$(VCInstallDir)lib',
+ '<(SHARED_INTERMEDIATE_DIR)/allocator',
+ ],
+ },
+ ],
+ },
+ {
+ 'target_name': 'allocator_unittests',
+ 'type': 'executable',
+ 'dependencies': [
+ 'allocator',
+ 'allocator_extension_thunks',
+ '../../testing/gtest.gyp:gtest',
+ ],
+ 'include_dirs': [
+ '.',
+ '<(tcmalloc_dir)/src/base',
+ '<(tcmalloc_dir)/src',
+ '../..',
+ ],
+ 'sources': [
+ 'allocator_unittests.cc',
+ '../profiler/alternate_timer.cc',
+ '../profiler/alternate_timer.h',
+ ],
+ },
+ {
+ 'target_name': 'allocator_extension_thunks_win64',
+ 'type': 'static_library',
+ 'sources': [
+ 'allocator_extension_thunks.cc',
+ 'allocator_extension_thunks.h',
+ ],
+ 'toolsets': ['host', 'target'],
+ 'include_dirs': [
+ '../../'
+ ],
+ 'configurations': {
+ 'Common_Base': {
+ 'msvs_target_platform': 'x64',
+ },
+ },
+ },
+ {
+ 'target_name': 'tcmalloc_unittest',
+ 'type': 'executable',
+ 'sources': [
+ 'tcmalloc_unittest.cc',
+ ],
+ 'include_dirs': [
+ '../..',
+ # For constants of TCMalloc.
+ '<(tcmalloc_dir)/src',
+ ],
+ 'dependencies': [
+ '../../testing/gtest.gyp:gtest',
+ '../base.gyp:base',
+ 'allocator',
+ ],
+ },
+ ],
+ }],
+ ['OS=="linux" and clang_type_profiler==1', {
+ # Some targets in this section undo dependencies and cflags_cc for
+ # type_profiler which build/common.gypi injects into all targets.
+ 'targets': [
+ {
+ 'target_name': 'type_profiler',
+ 'type': 'static_library',
+ 'dependencies!': [
+ 'type_profiler',
+ ],
+ 'cflags_cc!': [
+ '-fintercept-allocation-functions',
+ ],
+ 'include_dirs': [
+ '../..',
+ ],
+ 'sources': [
+ 'type_profiler.cc',
+ 'type_profiler.h',
+ 'type_profiler_control.h',
+ ],
+ 'toolsets': ['host', 'target'],
+ },
+ {
+ 'target_name': 'type_profiler_tcmalloc',
+ 'type': 'static_library',
+ 'dependencies!': [
+ 'type_profiler',
+ ],
+ 'cflags_cc!': [
+ '-fintercept-allocation-functions',
+ ],
+ 'include_dirs': [
+ '<(tcmalloc_dir)/src',
+ '../..',
+ ],
+ 'sources': [
+ 'type_profiler_tcmalloc.cc',
+ 'type_profiler_tcmalloc.h',
+ '<(tcmalloc_dir)/src/gperftools/type_profiler_map.h',
+ '<(tcmalloc_dir)/src/type_profiler_map.cc',
+ ],
+ },
+ {
+ 'target_name': 'type_profiler_unittests',
+ 'type': 'executable',
+ 'dependencies': [
+ '../../testing/gtest.gyp:gtest',
+ '../base.gyp:base',
+ 'allocator',
+ 'type_profiler_tcmalloc',
+ ],
+ 'include_dirs': [
+ '../..',
+ ],
+ 'sources': [
+ 'type_profiler_control.cc',
+ 'type_profiler_control.h',
+ 'type_profiler_unittests.cc',
+ ],
+ },
+ {
+ 'target_name': 'type_profiler_map_unittests',
+ 'type': 'executable',
+ 'dependencies': [
+ '../../testing/gtest.gyp:gtest',
+ '../base.gyp:base',
+ 'allocator',
+ ],
+ 'dependencies!': [
+ 'type_profiler',
+ ],
+ 'cflags_cc!': [
+ '-fintercept-allocation-functions',
+ ],
+ 'include_dirs': [
+ '<(tcmalloc_dir)/src',
+ '../..',
+ ],
+ 'sources': [
+ 'type_profiler_map_unittests.cc',
+ '<(tcmalloc_dir)/src/gperftools/type_profiler_map.h',
+ '<(tcmalloc_dir)/src/type_profiler_map.cc',
+ ],
+ },
+ ],
+ }],
+ ],
+}
diff --git a/src/base/allocator/allocator_extension.cc b/src/base/allocator/allocator_extension.cc
new file mode 100644
index 0000000..83e460a
--- /dev/null
+++ b/src/base/allocator/allocator_extension.cc
@@ -0,0 +1,56 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/allocator/allocator_extension.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace allocator {
+
+bool GetAllocatorWasteSize(size_t* size) {
+ thunks::GetAllocatorWasteSizeFunction get_allocator_waste_size_function =
+ thunks::GetGetAllocatorWasteSizeFunction();
+ return get_allocator_waste_size_function != NULL &&
+ get_allocator_waste_size_function(size);
+}
+
+void GetStats(char* buffer, int buffer_length) {
+ DCHECK_GT(buffer_length, 0);
+ thunks::GetStatsFunction get_stats_function = thunks::GetGetStatsFunction();
+ if (get_stats_function)
+ get_stats_function(buffer, buffer_length);
+ else
+ buffer[0] = '\0';
+}
+
+void ReleaseFreeMemory() {
+ thunks::ReleaseFreeMemoryFunction release_free_memory_function =
+ thunks::GetReleaseFreeMemoryFunction();
+ if (release_free_memory_function)
+ release_free_memory_function();
+}
+
+void SetGetAllocatorWasteSizeFunction(
+ thunks::GetAllocatorWasteSizeFunction get_allocator_waste_size_function) {
+ DCHECK_EQ(thunks::GetGetAllocatorWasteSizeFunction(),
+ reinterpret_cast<thunks::GetAllocatorWasteSizeFunction>(NULL));
+ thunks::SetGetAllocatorWasteSizeFunction(get_allocator_waste_size_function);
+}
+
+void SetGetStatsFunction(thunks::GetStatsFunction get_stats_function) {
+ DCHECK_EQ(thunks::GetGetStatsFunction(),
+ reinterpret_cast<thunks::GetStatsFunction>(NULL));
+ thunks::SetGetStatsFunction(get_stats_function);
+}
+
+void SetReleaseFreeMemoryFunction(
+ thunks::ReleaseFreeMemoryFunction release_free_memory_function) {
+ DCHECK_EQ(thunks::GetReleaseFreeMemoryFunction(),
+ reinterpret_cast<thunks::ReleaseFreeMemoryFunction>(NULL));
+ thunks::SetReleaseFreeMemoryFunction(release_free_memory_function);
+}
+
+} // namespace allocator
+} // namespace base
diff --git a/src/base/allocator/allocator_extension.h b/src/base/allocator/allocator_extension.h
new file mode 100644
index 0000000..de3119f
--- /dev/null
+++ b/src/base/allocator/allocator_extension.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ALLOCATOR_ALLOCATOR_EXTENSION_H
+#define BASE_ALLOCATOR_ALLOCATOR_EXTENSION_H
+
+#include <stddef.h> // for size_t
+
+#include "base/allocator/allocator_extension_thunks.h"
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace allocator {
+
+// Request the allocator to report value of its waste memory size.
+// Waste size corresponds to memory that has been allocated from the OS but
+// not passed up to the application. It e.g. includes memory retained by free
+// lists, internal data, chunks padding, etc.
+//
+// |size| pointer to the returned value, must be not NULL.
+// Returns true if the value has been returned, false otherwise.
+BASE_EXPORT bool GetAllocatorWasteSize(size_t* size);
+
+// Request that the allocator print a human-readable description of the current
+// state of the allocator into a null-terminated string in the memory segment
+// buffer[0,buffer_length-1].
+//
+// |buffer| must point to a valid piece of memory
+// |buffer_length| must be > 0.
+BASE_EXPORT void GetStats(char* buffer, int buffer_length);
+
+// Request that the allocator release any free memory it knows about to the
+// system.
+BASE_EXPORT void ReleaseFreeMemory();
+
+
+// These settings allow specifying a callback used to implement the allocator
+// extension functions. These are optional, but if set they must only be set
+// once. These will typically called in an allocator-specific initialization
+// routine.
+//
+// No threading promises are made. The caller is responsible for making sure
+// these pointers are set before any other threads attempt to call the above
+// functions.
+BASE_EXPORT void SetGetAllocatorWasteSizeFunction(
+ thunks::GetAllocatorWasteSizeFunction get_allocator_waste_size_function);
+
+BASE_EXPORT void SetGetStatsFunction(
+ thunks::GetStatsFunction get_stats_function);
+
+BASE_EXPORT void SetReleaseFreeMemoryFunction(
+ thunks::ReleaseFreeMemoryFunction release_free_memory_function);
+
+} // namespace allocator
+} // namespace base
+
+#endif
diff --git a/src/base/allocator/allocator_extension_thunks.cc b/src/base/allocator/allocator_extension_thunks.cc
new file mode 100644
index 0000000..e4024fb
--- /dev/null
+++ b/src/base/allocator/allocator_extension_thunks.cc
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/allocator/allocator_extension_thunks.h"
+
+#include <cstddef> // for NULL
+
+namespace base {
+namespace allocator {
+namespace thunks {
+
+// This slightly odd translation unit exists because of the peculularity of how
+// allocator_unittests work on windows. That target has to perform
+// tcmalloc-specific initialization on windows, but it cannot depend on base
+// otherwise. This target sits in the middle - base and allocator_unittests
+// can depend on it. This file can't depend on anything else in base, including
+// logging.
+
+static GetAllocatorWasteSizeFunction g_get_allocator_waste_size_function = NULL;
+static GetStatsFunction g_get_stats_function = NULL;
+static ReleaseFreeMemoryFunction g_release_free_memory_function = NULL;
+
+void SetGetAllocatorWasteSizeFunction(
+ GetAllocatorWasteSizeFunction get_allocator_waste_size_function) {
+ g_get_allocator_waste_size_function = get_allocator_waste_size_function;
+}
+
+GetAllocatorWasteSizeFunction GetGetAllocatorWasteSizeFunction() {
+ return g_get_allocator_waste_size_function;
+}
+
+void SetGetStatsFunction(GetStatsFunction get_stats_function) {
+ g_get_stats_function = get_stats_function;
+}
+
+GetStatsFunction GetGetStatsFunction() {
+ return g_get_stats_function;
+}
+
+void SetReleaseFreeMemoryFunction(
+ ReleaseFreeMemoryFunction release_free_memory_function) {
+ g_release_free_memory_function = release_free_memory_function;
+}
+
+ReleaseFreeMemoryFunction GetReleaseFreeMemoryFunction() {
+ return g_release_free_memory_function;
+}
+
+} // namespace thunks
+} // namespace allocator
+} // namespace base
diff --git a/src/base/allocator/allocator_extension_thunks.h b/src/base/allocator/allocator_extension_thunks.h
new file mode 100644
index 0000000..1e97a84
--- /dev/null
+++ b/src/base/allocator/allocator_extension_thunks.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ALLOCATOR_ALLOCATOR_THUNKS_EXTENSION_H
+#define BASE_ALLOCATOR_ALLOCATOR_THUNKS_EXTENSION_H
+
+#include <stddef.h> // for size_t
+
+namespace base {
+namespace allocator {
+namespace thunks {
+
+// WARNING: You probably don't want to use this file unless you are routing a
+// new allocator extension from a specific allocator implementation to base.
+// See allocator_extension.h to see the interface that base exports.
+
+typedef bool (*GetAllocatorWasteSizeFunction)(size_t* size);
+void SetGetAllocatorWasteSizeFunction(
+ GetAllocatorWasteSizeFunction get_allocator_waste_size_function);
+GetAllocatorWasteSizeFunction GetGetAllocatorWasteSizeFunction();
+
+typedef void (*GetStatsFunction)(char* buffer, int buffer_length);
+void SetGetStatsFunction(GetStatsFunction get_stats_function);
+GetStatsFunction GetGetStatsFunction();
+
+typedef void (*ReleaseFreeMemoryFunction)();
+void SetReleaseFreeMemoryFunction(
+ ReleaseFreeMemoryFunction release_free_memory_function);
+ReleaseFreeMemoryFunction GetReleaseFreeMemoryFunction();
+
+} // namespace thunks
+} // namespace allocator
+} // namespace base
+
+#endif
diff --git a/src/base/allocator/allocator_shim.cc b/src/base/allocator/allocator_shim.cc
new file mode 100644
index 0000000..6e41327
--- /dev/null
+++ b/src/base/allocator/allocator_shim.cc
@@ -0,0 +1,431 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/allocator/allocator_shim.h"
+
+#include <config.h>
+#include "base/allocator/allocator_extension_thunks.h"
+#include "base/profiler/alternate_timer.h"
+#include "base/sysinfo.h"
+#include "jemalloc.h"
+
+// When defined, different heap allocators can be used via an environment
+// variable set before running the program. This may reduce the amount
+// of inlining that we get with malloc/free/etc. Disabling makes it
+// so that only tcmalloc can be used.
+#define ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+
+// TODO(mbelshe): Ensure that all calls to tcmalloc have the proper call depth
+// from the "user code" so that debugging tools (HeapChecker) can work.
+
+// __THROW is defined in glibc systems. It means, counter-intuitively,
+// "This function will never throw an exception." It's an optional
+// optimization tool, but we may need to use it to match glibc prototypes.
+#ifndef __THROW // I guess we're not on a glibc system
+# define __THROW // __THROW is just an optimization, so ok to make it ""
+#endif
+
+// new_mode behaves similarly to MSVC's _set_new_mode.
+// If flag is 0 (default), calls to malloc will behave normally.
+// If flag is 1, calls to malloc will behave like calls to new,
+// and the std_new_handler will be invoked on failure.
+// Can be set by calling _set_new_mode().
+static int new_mode = 0;
+
+typedef enum {
+ TCMALLOC, // TCMalloc is the default allocator.
+ JEMALLOC, // JEMalloc.
+ WINHEAP, // Windows Heap (standard Windows allocator).
+ WINLFH, // Windows LFH Heap.
+} Allocator;
+
+// This is the default allocator. This value can be changed at startup by
+// specifying environment variables shown below it.
+// See SetupSubprocessAllocator() to specify a default secondary (subprocess)
+// allocator.
+// TODO(jar): Switch to using TCMALLOC for the renderer as well.
+static Allocator allocator = TCMALLOC;
+
+// The names of the environment variables that can optionally control the
+// selection of the allocator. The primary may be used to control overall
+// allocator selection, and the secondary can be used to specify an allocator
+// to use in sub-processes.
+static const char primary_name[] = "CHROME_ALLOCATOR";
+static const char secondary_name[] = "CHROME_ALLOCATOR_2";
+
+// We include tcmalloc and the win_allocator to get as much inlining as
+// possible.
+#include "debugallocation_shim.cc"
+#include "win_allocator.cc"
+
+// Forward declarations from jemalloc.
+extern "C" {
+void* je_malloc(size_t s);
+void* je_realloc(void* p, size_t s);
+void je_free(void* s);
+size_t je_msize(void* p);
+bool je_malloc_init_hard();
+void* je_memalign(size_t a, size_t s);
+}
+
+extern "C" {
+
+// Call the new handler, if one has been set.
+// Returns true on successfully calling the handler, false otherwise.
+inline bool call_new_handler(bool nothrow) {
+ // Get the current new handler. NB: this function is not
+ // thread-safe. We make a feeble stab at making it so here, but
+ // this lock only protects against tcmalloc interfering with
+ // itself, not with other libraries calling set_new_handler.
+ std::new_handler nh;
+ {
+ SpinLockHolder h(&set_new_handler_lock);
+ nh = std::set_new_handler(0);
+ (void) std::set_new_handler(nh);
+ }
+#if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS)
+ if (!nh)
+ return false;
+ // Since exceptions are disabled, we don't really know if new_handler
+ // failed. Assume it will abort if it fails.
+ (*nh)();
+ return false; // break out of the retry loop.
+#else
+ // If no new_handler is established, the allocation failed.
+ if (!nh) {
+ if (nothrow)
+ return 0;
+ throw std::bad_alloc();
+ }
+ // Otherwise, try the new_handler. If it returns, retry the
+ // allocation. If it throws std::bad_alloc, fail the allocation.
+ // if it throws something else, don't interfere.
+ try {
+ (*nh)();
+ } catch (const std::bad_alloc&) {
+ if (!nothrow)
+ throw;
+ return true;
+ }
+#endif // (defined(__GNUC__) && !defined(__EXCEPTIONS)) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS)
+}
+
+void* malloc(size_t size) __THROW {
+ void* ptr;
+ for (;;) {
+#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+ switch (allocator) {
+ case JEMALLOC:
+ ptr = je_malloc(size);
+ break;
+ case WINHEAP:
+ case WINLFH:
+ ptr = win_heap_malloc(size);
+ break;
+ case TCMALLOC:
+ default:
+ ptr = do_malloc(size);
+ break;
+ }
+#else
+ // TCMalloc case.
+ ptr = do_malloc(size);
+#endif
+ if (ptr)
+ return ptr;
+
+ if (!new_mode || !call_new_handler(true))
+ break;
+ }
+ return ptr;
+}
+
+void free(void* p) __THROW {
+#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+ switch (allocator) {
+ case JEMALLOC:
+ je_free(p);
+ return;
+ case WINHEAP:
+ case WINLFH:
+ win_heap_free(p);
+ return;
+ }
+#endif
+ // TCMalloc case.
+ do_free(p);
+}
+
+void* realloc(void* ptr, size_t size) __THROW {
+ // Webkit is brittle for allocators that return NULL for malloc(0). The
+ // realloc(0, 0) code path does not guarantee a non-NULL return, so be sure
+ // to call malloc for this case.
+ if (!ptr)
+ return malloc(size);
+
+ void* new_ptr;
+ for (;;) {
+#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+ switch (allocator) {
+ case JEMALLOC:
+ new_ptr = je_realloc(ptr, size);
+ break;
+ case WINHEAP:
+ case WINLFH:
+ new_ptr = win_heap_realloc(ptr, size);
+ break;
+ case TCMALLOC:
+ default:
+ new_ptr = do_realloc(ptr, size);
+ break;
+ }
+#else
+ // TCMalloc case.
+ new_ptr = do_realloc(ptr, size);
+#endif
+
+ // Subtle warning: NULL return does not alwas indicate out-of-memory. If
+ // the requested new size is zero, realloc should free the ptr and return
+ // NULL.
+ if (new_ptr || !size)
+ return new_ptr;
+ if (!new_mode || !call_new_handler(true))
+ break;
+ }
+ return new_ptr;
+}
+
+// TODO(mbelshe): Implement this for other allocators.
+void malloc_stats(void) __THROW {
+#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+ switch (allocator) {
+ case JEMALLOC:
+ // No stats.
+ return;
+ case WINHEAP:
+ case WINLFH:
+ // No stats.
+ return;
+ }
+#endif
+ tc_malloc_stats();
+}
+
+#ifdef WIN32
+
+extern "C" size_t _msize(void* p) {
+#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+ switch (allocator) {
+ case JEMALLOC:
+ return je_msize(p);
+ case WINHEAP:
+ case WINLFH:
+ return win_heap_msize(p);
+ }
+#endif
+ return MallocExtension::instance()->GetAllocatedSize(p);
+}
+
+// This is included to resolve references from libcmt.
+extern "C" intptr_t _get_heap_handle() {
+ return 0;
+}
+
+static bool get_allocator_waste_size_thunk(size_t* size) {
+#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+ switch (allocator) {
+ case JEMALLOC:
+ case WINHEAP:
+ case WINLFH:
+ // TODO(alexeif): Implement for allocators other than tcmalloc.
+ return false;
+ }
+#endif
+ size_t heap_size, allocated_bytes, unmapped_bytes;
+ MallocExtension* ext = MallocExtension::instance();
+ if (ext->GetNumericProperty("generic.heap_size", &heap_size) &&
+ ext->GetNumericProperty("generic.current_allocated_bytes",
+ &allocated_bytes) &&
+ ext->GetNumericProperty("tcmalloc.pageheap_unmapped_bytes",
+ &unmapped_bytes)) {
+ *size = heap_size - allocated_bytes - unmapped_bytes;
+ return true;
+ }
+ return false;
+}
+
+static void get_stats_thunk(char* buffer, int buffer_length) {
+ MallocExtension::instance()->GetStats(buffer, buffer_length);
+}
+
+static void release_free_memory_thunk() {
+ MallocExtension::instance()->ReleaseFreeMemory();
+}
+
+// The CRT heap initialization stub.
+extern "C" int _heap_init() {
+#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+ const char* environment_value = GetenvBeforeMain(primary_name);
+ if (environment_value) {
+ if (!stricmp(environment_value, "jemalloc"))
+ allocator = JEMALLOC;
+ else if (!stricmp(environment_value, "winheap"))
+ allocator = WINHEAP;
+ else if (!stricmp(environment_value, "winlfh"))
+ allocator = WINLFH;
+ else if (!stricmp(environment_value, "tcmalloc"))
+ allocator = TCMALLOC;
+ }
+
+ switch (allocator) {
+ case JEMALLOC:
+ return je_malloc_init_hard() ? 0 : 1;
+ case WINHEAP:
+ return win_heap_init(false) ? 1 : 0;
+ case WINLFH:
+ return win_heap_init(true) ? 1 : 0;
+ case TCMALLOC:
+ default:
+ // fall through
+ break;
+ }
+#endif
+ // Initializing tcmalloc.
+ // We intentionally leak this object. It lasts for the process
+ // lifetime. Trying to teardown at _heap_term() is so late that
+ // you can't do anything useful anyway.
+ new TCMallocGuard();
+
+ // Provide optional hook for monitoring allocation quantities on a per-thread
+ // basis. Only set the hook if the environment indicates this needs to be
+ // enabled.
+ const char* profiling =
+ GetenvBeforeMain(tracked_objects::kAlternateProfilerTime);
+ if (profiling && *profiling == '1') {
+ tracked_objects::SetAlternateTimeSource(
+ tcmalloc::ThreadCache::GetBytesAllocatedOnCurrentThread,
+ tracked_objects::TIME_SOURCE_TYPE_TCMALLOC);
+ }
+
+ base::allocator::thunks::SetGetAllocatorWasteSizeFunction(
+ get_allocator_waste_size_thunk);
+ base::allocator::thunks::SetGetStatsFunction(get_stats_thunk);
+ base::allocator::thunks::SetReleaseFreeMemoryFunction(
+ release_free_memory_thunk);
+
+ return 1;
+}
+
+// The CRT heap cleanup stub.
+extern "C" void _heap_term() {}
+
+// We set this to 1 because part of the CRT uses a check of _crtheap != 0
+// to test whether the CRT has been initialized. Once we've ripped out
+// the allocators from libcmt, we need to provide this definition so that
+// the rest of the CRT is still usable.
+extern "C" void* _crtheap = reinterpret_cast<void*>(1);
+
+// Provide support for aligned memory through Windows only _aligned_malloc().
+void* _aligned_malloc(size_t size, size_t alignment) {
+ // _aligned_malloc guarantees parameter validation, so do so here. These
+ // checks are somewhat stricter than _aligned_malloc() since we're effectively
+ // using memalign() under the hood.
+ DCHECK_GT(size, 0U);
+ DCHECK_EQ(alignment & (alignment - 1), 0U);
+ DCHECK_EQ(alignment % sizeof(void*), 0U);
+
+ void* ptr;
+ for (;;) {
+#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+ switch (allocator) {
+ case JEMALLOC:
+ ptr = je_memalign(alignment, size);
+ break;
+ case WINHEAP:
+ case WINLFH:
+ ptr = win_heap_memalign(alignment, size);
+ break;
+ case TCMALLOC:
+ default:
+ ptr = tc_memalign(alignment, size);
+ break;
+ }
+#else
+ // TCMalloc case.
+ ptr = tc_memalign(alignment, size);
+#endif
+ if (ptr) {
+ // Sanity check alignment.
+ DCHECK_EQ(reinterpret_cast<uintptr_t>(ptr) & (alignment - 1), 0U);
+ return ptr;
+ }
+
+ if (!new_mode || !call_new_handler(true))
+ break;
+ }
+ return ptr;
+}
+
+void _aligned_free(void* p) {
+ // Both JEMalloc and TCMalloc return pointers from memalign() that are safe to
+ // use with free(). Pointers allocated with win_heap_memalign() MUST be freed
+ // via win_heap_memalign_free() since the aligned pointer is not the real one.
+#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+ switch (allocator) {
+ case JEMALLOC:
+ je_free(p);
+ return;
+ case WINHEAP:
+ case WINLFH:
+ win_heap_memalign_free(p);
+ return;
+ }
+#endif
+ // TCMalloc case.
+ do_free(p);
+}
+
+#endif // WIN32
+
+#include "generic_allocators.cc"
+
+} // extern C
+
+namespace base {
+namespace allocator {
+
+void SetupSubprocessAllocator() {
+#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+ size_t primary_length = 0;
+ getenv_s(&primary_length, NULL, 0, primary_name);
+
+ size_t secondary_length = 0;
+ char buffer[20];
+ getenv_s(&secondary_length, buffer, sizeof(buffer), secondary_name);
+ DCHECK_GT(sizeof(buffer), secondary_length);
+ buffer[sizeof(buffer) - 1] = '\0';
+
+ if (secondary_length || !primary_length) {
+ const char* secondary_value = secondary_length ? buffer : "TCMALLOC";
+ // Force renderer (or other subprocesses) to use secondary_value.
+ int ret_val = _putenv_s(primary_name, secondary_value);
+ DCHECK_EQ(0, ret_val);
+ }
+#endif // ENABLE_DYNAMIC_ALLOCATOR_SWITCHING
+}
+
+void* TCMallocDoMallocForTest(size_t size) {
+ return do_malloc(size);
+}
+
+void TCMallocDoFreeForTest(void* ptr) {
+ do_free(ptr);
+}
+
+size_t ExcludeSpaceForMarkForTest(size_t size) {
+ return ExcludeSpaceForMark(size);
+}
+
+} // namespace allocator.
+} // namespace base.
diff --git a/src/base/allocator/allocator_shim.h b/src/base/allocator/allocator_shim.h
new file mode 100644
index 0000000..e10fa8d
--- /dev/null
+++ b/src/base/allocator/allocator_shim.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ALLOCATOR_ALLOCATOR_SHIM_H_
+#define BASE_ALLOCATOR_ALLOCATOR_SHIM_H_
+
+namespace base {
+namespace allocator {
+
+// Resets the environment variable CHROME_ALLOCATOR to specify the choice to
+// be used by subprocesses. Priority is given to the current value of
+// CHROME_ALLOCATOR_2 (if specified), then CHROME_ALLOCATOR (if specified), and
+// then a default value (typically set to TCMALLOC).
+void SetupSubprocessAllocator();
+
+// Expose some of tcmalloc functions for test.
+void* TCMallocDoMallocForTest(size_t size);
+void TCMallocDoFreeForTest(void* ptr);
+size_t ExcludeSpaceForMarkForTest(size_t size);
+
+} // namespace allocator.
+} // namespace base.
+
+#endif // BASE_ALLOCATOR_ALLOCATOR_SHIM_H_
diff --git a/src/base/allocator/allocator_unittests.cc b/src/base/allocator/allocator_unittests.cc
new file mode 100644
index 0000000..3c455ba
--- /dev/null
+++ b/src/base/allocator/allocator_unittests.cc
@@ -0,0 +1,555 @@
+// Copyright (c) 2012 The Chromium Authors. 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 <algorithm> // for min()
+#include "base/atomicops.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Number of bits in a size_t.
+static const int kSizeBits = 8 * sizeof(size_t);
+// The maximum size of a size_t.
+static const size_t kMaxSize = ~static_cast<size_t>(0);
+// Maximum positive size of a size_t if it were signed.
+static const size_t kMaxSignedSize = ((size_t(1) << (kSizeBits-1)) - 1);
+
+#if !defined(__LB_SHELL__) && !defined(OS_STARBOARD)
+// An allocation size which is not too big to be reasonable.
+static const size_t kNotTooBig = 100000;
+// An allocation size which is just too big.
+static const size_t kTooBig = ~static_cast<size_t>(0);
+#endif
+
+namespace {
+
+using std::min;
+
+// Fill a buffer of the specified size with a predetermined pattern
+static void Fill(unsigned char* buffer, int n) {
+ for (int i = 0; i < n; i++) {
+ buffer[i] = (i & 0xff);
+ }
+}
+
+// Check that the specified buffer has the predetermined pattern
+// generated by Fill()
+static bool Valid(unsigned char* buffer, int n) {
+ for (int i = 0; i < n; i++) {
+ if (buffer[i] != (i & 0xff)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// Check that a buffer is completely zeroed.
+static bool IsZeroed(unsigned char* buffer, int n) {
+ for (int i = 0; i < n; i++) {
+ if (buffer[i] != 0) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// Check alignment
+static void CheckAlignment(void* p, int align) {
+ EXPECT_EQ(0, reinterpret_cast<uintptr_t>(p) & (align-1));
+}
+
+// Return the next interesting size/delta to check. Returns -1 if no more.
+static int NextSize(int size) {
+ if (size < 100)
+ return size+1;
+
+ if (size < 100000) {
+ // Find next power of two
+ int power = 1;
+ while (power < size)
+ power <<= 1;
+
+ // Yield (power-1, power, power+1)
+ if (size < power-1)
+ return power-1;
+
+ if (size == power-1)
+ return power;
+
+ assert(size == power);
+ return power+1;
+ } else {
+ return -1;
+ }
+}
+
+#if defined(__LB_SHELL__) || defined(OS_STARBOARD)
+#if defined(GG_ULONGLONG)
+// GG_ULONGLONG is already defined in base/port.h
+#undef GG_ULONGLONG
+#endif
+
+// namespace resolution for typedefs
+using base::subtle::AtomicWord;
+using base::subtle::Atomic32;
+#endif
+
+#define GG_ULONGLONG(x) static_cast<uint64>(x)
+
+template <class AtomicType>
+static void TestAtomicIncrement() {
+ // For now, we just test single threaded execution
+
+ // use a guard value to make sure the NoBarrier_AtomicIncrement doesn't go
+ // outside the expected address bounds. This is in particular to
+ // test that some future change to the asm code doesn't cause the
+ // 32-bit NoBarrier_AtomicIncrement to do the wrong thing on 64-bit machines.
+ struct {
+ AtomicType prev_word;
+ AtomicType count;
+ AtomicType next_word;
+ } s;
+
+ AtomicType prev_word_value, next_word_value;
+ memset(&prev_word_value, 0xFF, sizeof(AtomicType));
+ memset(&next_word_value, 0xEE, sizeof(AtomicType));
+
+ s.prev_word = prev_word_value;
+ s.count = 0;
+ s.next_word = next_word_value;
+
+ EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 1), 1);
+ EXPECT_EQ(s.count, 1);
+ EXPECT_EQ(s.prev_word, prev_word_value);
+ EXPECT_EQ(s.next_word, next_word_value);
+
+ EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 2), 3);
+ EXPECT_EQ(s.count, 3);
+ EXPECT_EQ(s.prev_word, prev_word_value);
+ EXPECT_EQ(s.next_word, next_word_value);
+
+ EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 3), 6);
+ EXPECT_EQ(s.count, 6);
+ EXPECT_EQ(s.prev_word, prev_word_value);
+ EXPECT_EQ(s.next_word, next_word_value);
+
+ EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -3), 3);
+ EXPECT_EQ(s.count, 3);
+ EXPECT_EQ(s.prev_word, prev_word_value);
+ EXPECT_EQ(s.next_word, next_word_value);
+
+ EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -2), 1);
+ EXPECT_EQ(s.count, 1);
+ EXPECT_EQ(s.prev_word, prev_word_value);
+ EXPECT_EQ(s.next_word, next_word_value);
+
+ EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), 0);
+ EXPECT_EQ(s.count, 0);
+ EXPECT_EQ(s.prev_word, prev_word_value);
+ EXPECT_EQ(s.next_word, next_word_value);
+
+ EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), -1);
+ EXPECT_EQ(s.count, -1);
+ EXPECT_EQ(s.prev_word, prev_word_value);
+ EXPECT_EQ(s.next_word, next_word_value);
+
+ EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -4), -5);
+ EXPECT_EQ(s.count, -5);
+ EXPECT_EQ(s.prev_word, prev_word_value);
+ EXPECT_EQ(s.next_word, next_word_value);
+
+ EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 5), 0);
+ EXPECT_EQ(s.count, 0);
+ EXPECT_EQ(s.prev_word, prev_word_value);
+ EXPECT_EQ(s.next_word, next_word_value);
+}
+
+
+#define NUM_BITS(T) (sizeof(T) * 8)
+
+
+template <class AtomicType>
+static void TestCompareAndSwap() {
+ AtomicType value = 0;
+ AtomicType prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 1);
+ EXPECT_EQ(1, value);
+ EXPECT_EQ(0, prev);
+
+ // Use test value that has non-zero bits in both halves, more for testing
+ // 64-bit implementation on 32-bit platforms.
+ const AtomicType k_test_val = (GG_ULONGLONG(1) <<
+ (NUM_BITS(AtomicType) - 2)) + 11;
+ value = k_test_val;
+ prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 5);
+ EXPECT_EQ(k_test_val, value);
+ EXPECT_EQ(k_test_val, prev);
+
+ value = k_test_val;
+ prev = base::subtle::NoBarrier_CompareAndSwap(&value, k_test_val, 5);
+ EXPECT_EQ(5, value);
+ EXPECT_EQ(k_test_val, prev);
+}
+
+
+template <class AtomicType>
+static void TestAtomicExchange() {
+ AtomicType value = 0;
+ AtomicType new_value = base::subtle::NoBarrier_AtomicExchange(&value, 1);
+ EXPECT_EQ(1, value);
+ EXPECT_EQ(0, new_value);
+
+ // Use test value that has non-zero bits in both halves, more for testing
+ // 64-bit implementation on 32-bit platforms.
+ const AtomicType k_test_val = (GG_ULONGLONG(1) <<
+ (NUM_BITS(AtomicType) - 2)) + 11;
+ value = k_test_val;
+ new_value = base::subtle::NoBarrier_AtomicExchange(&value, k_test_val);
+ EXPECT_EQ(k_test_val, value);
+ EXPECT_EQ(k_test_val, new_value);
+
+ value = k_test_val;
+ new_value = base::subtle::NoBarrier_AtomicExchange(&value, 5);
+ EXPECT_EQ(5, value);
+ EXPECT_EQ(k_test_val, new_value);
+}
+
+
+template <class AtomicType>
+static void TestAtomicIncrementBounds() {
+ // Test increment at the half-width boundary of the atomic type.
+ // It is primarily for testing at the 32-bit boundary for 64-bit atomic type.
+ AtomicType test_val = GG_ULONGLONG(1) << (NUM_BITS(AtomicType) / 2);
+ AtomicType value = test_val - 1;
+ AtomicType new_value = base::subtle::NoBarrier_AtomicIncrement(&value, 1);
+ EXPECT_EQ(test_val, value);
+ EXPECT_EQ(value, new_value);
+
+ base::subtle::NoBarrier_AtomicIncrement(&value, -1);
+ EXPECT_EQ(test_val - 1, value);
+}
+
+// This is a simple sanity check that values are correct. Not testing
+// atomicity
+template <class AtomicType>
+static void TestStore() {
+ const AtomicType kVal1 = static_cast<AtomicType>(0xa5a5a5a5a5a5a5a5LL);
+ const AtomicType kVal2 = static_cast<AtomicType>(-1);
+
+ AtomicType value;
+
+ base::subtle::NoBarrier_Store(&value, kVal1);
+ EXPECT_EQ(kVal1, value);
+ base::subtle::NoBarrier_Store(&value, kVal2);
+ EXPECT_EQ(kVal2, value);
+
+ base::subtle::Acquire_Store(&value, kVal1);
+ EXPECT_EQ(kVal1, value);
+ base::subtle::Acquire_Store(&value, kVal2);
+ EXPECT_EQ(kVal2, value);
+
+ base::subtle::Release_Store(&value, kVal1);
+ EXPECT_EQ(kVal1, value);
+ base::subtle::Release_Store(&value, kVal2);
+ EXPECT_EQ(kVal2, value);
+}
+
+// This is a simple sanity check that values are correct. Not testing
+// atomicity
+template <class AtomicType>
+static void TestLoad() {
+ const AtomicType kVal1 = static_cast<AtomicType>(0xa5a5a5a5a5a5a5a5LL);
+ const AtomicType kVal2 = static_cast<AtomicType>(-1);
+
+ AtomicType value;
+
+ value = kVal1;
+ EXPECT_EQ(kVal1, base::subtle::NoBarrier_Load(&value));
+ value = kVal2;
+ EXPECT_EQ(kVal2, base::subtle::NoBarrier_Load(&value));
+
+ value = kVal1;
+ EXPECT_EQ(kVal1, base::subtle::Acquire_Load(&value));
+ value = kVal2;
+ EXPECT_EQ(kVal2, base::subtle::Acquire_Load(&value));
+
+ value = kVal1;
+ EXPECT_EQ(kVal1, base::subtle::Release_Load(&value));
+ value = kVal2;
+ EXPECT_EQ(kVal2, base::subtle::Release_Load(&value));
+}
+
+template <class AtomicType>
+static void TestAtomicOps() {
+ TestCompareAndSwap<AtomicType>();
+ TestAtomicExchange<AtomicType>();
+ TestAtomicIncrementBounds<AtomicType>();
+ TestStore<AtomicType>();
+ TestLoad<AtomicType>();
+}
+
+static void TestCalloc(size_t n, size_t s, bool ok) {
+ char* p = reinterpret_cast<char*>(calloc(n, s));
+ if (!ok) {
+ EXPECT_EQ(NULL, p) << "calloc(n, s) should not succeed";
+ } else {
+ // TODO(__LB_SHELL__): This behavior is not defined by c++ standard.
+ // However it is possible that chromium expects it. We need to make sure
+ // these functions work the same way as expected by chromium when we override
+ // memory functions.
+ EXPECT_NE(reinterpret_cast<void*>(NULL), p) <<
+ "calloc(n, s) should succeed";
+ for (int i = 0; i < n*s; i++) {
+ EXPECT_EQ('\0', p[i]);
+ }
+ free(p);
+ }
+}
+
+#if !defined(__LB_SHELL__) && !defined(OS_STARBOARD)
+// Exceptions are disabled on lbshell and Starboard.
+
+// A global test counter for number of times the NewHandler is called.
+static int news_handled = 0;
+static void TestNewHandler() {
+ ++news_handled;
+ throw std::bad_alloc();
+}
+
+// Because we compile without exceptions, we expect these will not throw.
+static void TestOneNewWithoutExceptions(void* (*func)(size_t),
+ bool should_throw) {
+ // success test
+ try {
+ void* ptr = (*func)(kNotTooBig);
+ EXPECT_NE(reinterpret_cast<void*>(NULL), ptr) <<
+ "allocation should not have failed.";
+ } catch(...) {
+ EXPECT_EQ(0, 1) << "allocation threw unexpected exception.";
+ }
+
+ // failure test
+ try {
+ void* rv = (*func)(kTooBig);
+ EXPECT_EQ(NULL, rv);
+ EXPECT_FALSE(should_throw) << "allocation should have thrown.";
+ } catch(...) {
+ EXPECT_TRUE(should_throw) << "allocation threw unexpected exception.";
+ }
+}
+
+static void TestNothrowNew(void* (*func)(size_t)) {
+ news_handled = 0;
+
+ // test without new_handler:
+ std::new_handler saved_handler = std::set_new_handler(0);
+ TestOneNewWithoutExceptions(func, false);
+
+ // test with new_handler:
+ std::set_new_handler(TestNewHandler);
+ TestOneNewWithoutExceptions(func, true);
+ EXPECT_EQ(news_handled, 1) << "nothrow new_handler was not called.";
+ std::set_new_handler(saved_handler);
+}
+#endif
+} // namespace
+
+//-----------------------------------------------------------------------------
+
+TEST(Atomics, AtomicIncrementWord) {
+ TestAtomicIncrement<AtomicWord>();
+}
+
+TEST(Atomics, AtomicIncrement32) {
+ TestAtomicIncrement<Atomic32>();
+}
+
+TEST(Atomics, AtomicOpsWord) {
+ TestAtomicIncrement<AtomicWord>();
+}
+
+TEST(Atomics, AtomicOps32) {
+ TestAtomicIncrement<Atomic32>();
+}
+
+TEST(Allocators, Malloc) {
+ // Try allocating data with a bunch of alignments and sizes
+ for (int size = 1; size < 1048576; size *= 2) {
+ unsigned char* ptr = reinterpret_cast<unsigned char*>(malloc(size));
+ CheckAlignment(ptr, 2); // Should be 2 byte aligned
+ Fill(ptr, size);
+ EXPECT_TRUE(Valid(ptr, size));
+ free(ptr);
+ }
+}
+
+TEST(Allocators, Calloc) {
+ TestCalloc(0, 0, true);
+ TestCalloc(0, 1, true);
+ TestCalloc(1, 1, true);
+ TestCalloc(1<<10, 0, true);
+ TestCalloc(1<<20, 0, true);
+ TestCalloc(0, 1<<10, true);
+ TestCalloc(0, 1<<20, true);
+ TestCalloc(1<<20, 2, true);
+ TestCalloc(2, 1<<20, true);
+ TestCalloc(1000, 1000, true);
+
+ TestCalloc(kMaxSize, 2, false);
+ TestCalloc(2, kMaxSize, false);
+ TestCalloc(kMaxSize, kMaxSize, false);
+
+ TestCalloc(kMaxSignedSize, 3, false);
+ TestCalloc(3, kMaxSignedSize, false);
+ TestCalloc(kMaxSignedSize, kMaxSignedSize, false);
+}
+
+#if !defined(__LB_SHELL__) && !defined(OS_STARBOARD)
+// Exceptions are disabled on lbshell.
+TEST(Allocators, New) {
+ TestNothrowNew(&::operator new);
+ TestNothrowNew(&::operator new[]);
+}
+#endif
+
+#if !defined(__LB_SHELL__) && !defined(OS_STARBOARD)
+// The test assumes the memory space to be very empty
+// and doesn't work on lb_shell platforms.
+
+// This makes sure that reallocing a small number of bytes in either
+// direction doesn't cause us to allocate new memory.
+TEST(Allocators, Realloc1) {
+ int start_sizes[] = { 100, 1000, 10000, 100000 };
+ int deltas[] = { 1, -2, 4, -8, 16, -32, 64, -128 };
+
+ for (int s = 0; s < sizeof(start_sizes)/sizeof(*start_sizes); ++s) {
+ void* p = malloc(start_sizes[s]);
+ ASSERT_TRUE(p);
+ // The larger the start-size, the larger the non-reallocing delta.
+ for (int d = 0; d < s*2; ++d) {
+ void* new_p = realloc(p, start_sizes[s] + deltas[d]);
+ ASSERT_EQ(p, new_p); // realloc should not allocate new memory
+ }
+ // Test again, but this time reallocing smaller first.
+ for (int d = 0; d < s*2; ++d) {
+ void* new_p = realloc(p, start_sizes[s] - deltas[d]);
+ ASSERT_EQ(p, new_p); // realloc should not allocate new memory
+ }
+ free(p);
+ }
+}
+#endif
+
+TEST(Allocators, Realloc2) {
+ for (int src_size = 0; src_size >= 0; src_size = NextSize(src_size)) {
+ for (int dst_size = 0; dst_size >= 0; dst_size = NextSize(dst_size)) {
+ unsigned char* src = reinterpret_cast<unsigned char*>(malloc(src_size));
+ Fill(src, src_size);
+ unsigned char* dst =
+ reinterpret_cast<unsigned char*>(realloc(src, dst_size));
+ EXPECT_TRUE(Valid(dst, min(src_size, dst_size)));
+ Fill(dst, dst_size);
+ EXPECT_TRUE(Valid(dst, dst_size));
+ if (dst != NULL) free(dst);
+ }
+ }
+
+ // Now make sure realloc works correctly even when we overflow the
+ // packed cache, so some entries are evicted from the cache.
+ // The cache has 2^12 entries, keyed by page number.
+ const int kNumEntries = 1 << 14;
+ int** p = reinterpret_cast<int**>(malloc(sizeof(*p) * kNumEntries));
+ int sum = 0;
+ for (int i = 0; i < kNumEntries; i++) {
+ // no page size is likely to be bigger than 8192?
+ p[i] = reinterpret_cast<int*>(malloc(8192));
+ p[i][1000] = i; // use memory deep in the heart of p
+ }
+ for (int i = 0; i < kNumEntries; i++) {
+ p[i] = reinterpret_cast<int*>(realloc(p[i], 9000));
+ }
+ for (int i = 0; i < kNumEntries; i++) {
+ sum += p[i][1000];
+ free(p[i]);
+ }
+ EXPECT_EQ(kNumEntries/2 * (kNumEntries - 1), sum); // assume kNE is even
+ free(p);
+}
+
+// TODO(__LB_SHELL__): This behavior is not defined by c++ standard.
+// However it is possible that chromium expects it. We need to make sure
+// these functions work the same way as expected by chromium when we override
+// memory functions.
+TEST(Allocators, ReallocZero) {
+ // Test that realloc to zero does not return NULL.
+ for (int size = 0; size >= 0; size = NextSize(size)) {
+ char* ptr = reinterpret_cast<char*>(malloc(size));
+ EXPECT_NE(static_cast<char*>(NULL), ptr);
+ ptr = reinterpret_cast<char*>(realloc(ptr, 0));
+ EXPECT_NE(static_cast<char*>(NULL), ptr);
+ if (ptr)
+ free(ptr);
+ }
+}
+
+#ifdef WIN32
+// Test recalloc
+TEST(Allocators, Recalloc) {
+ for (int src_size = 0; src_size >= 0; src_size = NextSize(src_size)) {
+ for (int dst_size = 0; dst_size >= 0; dst_size = NextSize(dst_size)) {
+ unsigned char* src =
+ reinterpret_cast<unsigned char*>(_recalloc(NULL, 1, src_size));
+ EXPECT_TRUE(IsZeroed(src, src_size));
+ Fill(src, src_size);
+ unsigned char* dst =
+ reinterpret_cast<unsigned char*>(_recalloc(src, 1, dst_size));
+ EXPECT_TRUE(Valid(dst, min(src_size, dst_size)));
+ Fill(dst, dst_size);
+ EXPECT_TRUE(Valid(dst, dst_size));
+ if (dst != NULL)
+ free(dst);
+ }
+ }
+}
+
+// Test windows specific _aligned_malloc() and _aligned_free() methods.
+TEST(Allocators, AlignedMalloc) {
+ // Try allocating data with a bunch of alignments and sizes
+ static const int kTestAlignments[] = {8, 16, 256, 4096, 8192, 16384};
+ for (int size = 1; size > 0; size = NextSize(size)) {
+ for (int i = 0; i < ARRAYSIZE(kTestAlignments); ++i) {
+ unsigned char* ptr = static_cast<unsigned char*>(
+ _aligned_malloc(size, kTestAlignments[i]));
+ CheckAlignment(ptr, kTestAlignments[i]);
+ Fill(ptr, size);
+ EXPECT_TRUE(Valid(ptr, size));
+
+ // Make a second allocation of the same size and alignment to prevent
+ // allocators from passing this test by accident. Per jar, tcmalloc
+ // provides allocations for new (never before seen) sizes out of a thread
+ // local heap of a given "size class." Each time the test requests a new
+ // size, it will usually get the first element of a span, which is a
+ // 4K aligned allocation.
+ unsigned char* ptr2 = static_cast<unsigned char*>(
+ _aligned_malloc(size, kTestAlignments[i]));
+ CheckAlignment(ptr2, kTestAlignments[i]);
+ Fill(ptr2, size);
+ EXPECT_TRUE(Valid(ptr2, size));
+
+ // Should never happen, but sanity check just in case.
+ ASSERT_NE(ptr, ptr2);
+ _aligned_free(ptr);
+ _aligned_free(ptr2);
+ }
+ }
+}
+
+#endif
+
+#if !defined(__LB_SHELL__) && !defined(OS_STARBOARD)
+// main defined in run_all_unittests
+int main(int argc, char** argv) {
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
+#endif
diff --git a/src/base/allocator/debugallocation_shim.cc b/src/base/allocator/debugallocation_shim.cc
new file mode 100644
index 0000000..d1cf52a
--- /dev/null
+++ b/src/base/allocator/debugallocation_shim.cc
@@ -0,0 +1,9 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#if defined(TCMALLOC_FOR_DEBUGALLOCATION)
+#include "third_party/tcmalloc/chromium/src/debugallocation.cc"
+#else
+#include "third_party/tcmalloc/chromium/src/tcmalloc.cc"
+#endif
diff --git a/src/base/allocator/generic_allocators.cc b/src/base/allocator/generic_allocators.cc
new file mode 100644
index 0000000..d4cf19e
--- /dev/null
+++ b/src/base/allocator/generic_allocators.cc
@@ -0,0 +1,168 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// When possible, we implement allocator functions on top of the basic
+// low-level functions malloc() and free(). This way, including a new
+// allocator is as simple as providing just a small interface.
+//
+// As such, this file should not contain any allocator-specific code.
+
+// Implement a C++ style allocation, which always calls the new_handler
+// on failure.
+inline void* generic_cpp_alloc(size_t size, bool nothrow) {
+ void* ptr;
+ for (;;) {
+ ptr = malloc(size);
+ if (ptr)
+ return ptr;
+ if (!call_new_handler(nothrow))
+ break;
+ }
+ return ptr;
+}
+
+extern "C++" {
+
+void* __cdecl operator new(size_t size) {
+ return generic_cpp_alloc(size, false);
+}
+
+void operator delete(void* p) __THROW {
+ free(p);
+}
+
+void* operator new[](size_t size) {
+ return generic_cpp_alloc(size, false);
+}
+
+void operator delete[](void* p) __THROW {
+ free(p);
+}
+
+void* operator new(size_t size, const std::nothrow_t& nt) __THROW {
+ return generic_cpp_alloc(size, true);
+}
+
+void* operator new[](size_t size, const std::nothrow_t& nt) __THROW {
+ return generic_cpp_alloc(size, true);
+}
+
+// This function behaves similarly to MSVC's _set_new_mode.
+// If flag is 0 (default), calls to malloc will behave normally.
+// If flag is 1, calls to malloc will behave like calls to new,
+// and the std_new_handler will be invoked on failure.
+// Returns the previous mode.
+int _set_new_mode(int flag) __THROW {
+ int old_mode = new_mode;
+ new_mode = flag;
+ return old_mode;
+}
+
+} // extern "C++"
+
+extern "C" {
+
+void* calloc(size_t n, size_t elem_size) __THROW {
+ // Overflow check
+ const size_t size = n * elem_size;
+ if (elem_size != 0 && size / elem_size != n) return NULL;
+
+ void* result = malloc(size);
+ if (result != NULL) {
+ memset(result, 0, size);
+ }
+ return result;
+}
+
+void cfree(void* p) __THROW {
+ free(p);
+}
+
+#ifdef WIN32
+
+void* _recalloc(void* p, size_t n, size_t elem_size) {
+ if (!p)
+ return calloc(n, elem_size);
+
+ // This API is a bit odd.
+ // Note: recalloc only guarantees zeroed memory when p is NULL.
+ // Generally, calls to malloc() have padding. So a request
+ // to malloc N bytes actually malloc's N+x bytes. Later, if
+ // that buffer is passed to recalloc, we don't know what N
+ // was anymore. We only know what N+x is. As such, there is
+ // no way to know what to zero out.
+ const size_t size = n * elem_size;
+ if (elem_size != 0 && size / elem_size != n) return NULL;
+ return realloc(p, size);
+}
+
+void* _calloc_impl(size_t n, size_t size) {
+ return calloc(n, size);
+}
+
+#ifndef NDEBUG
+#undef malloc
+#undef free
+#undef calloc
+
+static int error_handler(int reportType) {
+ switch (reportType) {
+ case 0: // _CRT_WARN
+ __debugbreak();
+ return 0;
+
+ case 1: // _CRT_ERROR
+ __debugbreak();
+ return 0;
+
+ case 2: // _CRT_ASSERT
+ __debugbreak();
+ return 0;
+ }
+ char* p = NULL;
+ *p = '\0';
+ return 0;
+}
+
+int _CrtDbgReport(int reportType,
+ const char*,
+ int, const char*,
+ const char*,
+ ...) {
+ return error_handler(reportType);
+}
+
+int _CrtDbgReportW(int reportType,
+ const wchar_t*,
+ int, const wchar_t*,
+ const wchar_t*,
+ ...) {
+ return error_handler(reportType);
+}
+
+int _CrtSetReportMode(int, int) {
+ return 0;
+}
+
+void* _malloc_dbg(size_t size, int , const char*, int) {
+ return malloc(size);
+}
+
+void* _realloc_dbg(void* ptr, size_t size, int, const char*, int) {
+ return realloc(ptr, size);
+}
+
+void _free_dbg(void* ptr, int) {
+ free(ptr);
+}
+
+void* _calloc_dbg(size_t n, size_t size, int, const char*, int) {
+ return calloc(n, size);
+}
+#endif // NDEBUG
+
+#endif // WIN32
+
+} // extern C
+
diff --git a/src/base/allocator/prep_libc.py b/src/base/allocator/prep_libc.py
new file mode 100755
index 0000000..be7030f
--- /dev/null
+++ b/src/base/allocator/prep_libc.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# This script takes libcmt.lib for VS2005/08/10 and removes the allocation
+# related functions from it.
+#
+# Usage: prep_libc.py <VCInstallDir> <OutputDir>
+#
+# VCInstallDir is the path where VC is installed, something like:
+# C:\Program Files\Microsoft Visual Studio 8\VC\
+#
+# OutputDir is the directory where the modified libcmt file should be stored.
+
+import os
+import shutil
+import subprocess
+import sys
+
+def run(command, filter=None):
+ """Run |command|, removing any lines that match |filter|. The filter is
+ to remove the echoing of input filename that 'lib' does."""
+ popen = subprocess.Popen(
+ command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ out, _ = popen.communicate()
+ for line in out.splitlines():
+ if filter and line.strip() != filter:
+ print line
+ return popen.returncode
+
+def main():
+ vs_install_dir = sys.argv[1]
+ outdir = sys.argv[2]
+ output_lib = os.path.join(outdir, 'libcmt.lib')
+ shutil.copyfile(os.path.join(vs_install_dir, 'libcmt.lib'), output_lib)
+ shutil.copyfile(os.path.join(vs_install_dir, 'libcmt.pdb'),
+ os.path.join(outdir, 'libcmt.pdb'))
+ vspaths = [
+ 'build\\intel\\mt_obj\\',
+ 'f:\\dd\\vctools\\crt_bld\\SELF_X86\\crt\\src\\build\\INTEL\\mt_obj\\',
+ 'F:\\dd\\vctools\\crt_bld\\SELF_X86\\crt\\src\\build\\INTEL\\mt_obj\\nativec\\\\',
+ 'F:\\dd\\vctools\\crt_bld\\SELF_X86\\crt\\src\\build\\INTEL\\mt_obj\\nativecpp\\\\',
+ ]
+ objfiles = ['malloc', 'free', 'realloc', 'new', 'delete', 'new2', 'delete2',
+ 'align', 'msize', 'heapinit', 'expand', 'heapchk', 'heapwalk',
+ 'heapmin', 'sbheap', 'calloc', 'recalloc', 'calloc_impl',
+ 'new_mode', 'newopnt']
+ for obj in objfiles:
+ for vspath in vspaths:
+ cmd = ('lib /nologo /ignore:4006,4014,4221 /remove:%s%s.obj %s' %
+ (vspath, obj, output_lib))
+ run(cmd, obj + '.obj')
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/src/base/allocator/tcmalloc_unittest.cc b/src/base/allocator/tcmalloc_unittest.cc
new file mode 100644
index 0000000..053a9d5
--- /dev/null
+++ b/src/base/allocator/tcmalloc_unittest.cc
@@ -0,0 +1,81 @@
+// Copyright (c) 2012 The Chromium Authors. 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 "base/allocator/allocator_shim.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+// TCMalloc header files
+#include "common.h" // For TCMalloc constants like page size, etc.
+
+using base::allocator::TCMallocDoMallocForTest;
+using base::allocator::TCMallocDoFreeForTest;
+using base::allocator::ExcludeSpaceForMarkForTest;
+
+TEST(TCMallocFreeCheck, BadPointerInFirstPageOfTheLargeObject) {
+ char* p = reinterpret_cast<char*>(
+ TCMallocDoMallocForTest(ExcludeSpaceForMarkForTest(kMaxSize + 1)));
+ for (int offset = 1; offset < kPageSize ; offset <<= 1) {
+ ASSERT_DEATH(TCMallocDoFreeForTest(p + offset),
+ "Pointer is not pointing to the start of a span");
+ }
+}
+
+TEST(TCMallocFreeCheck, BadPageAlignedPointerInsideLargeObject) {
+ char* p = reinterpret_cast<char*>(
+ TCMallocDoMallocForTest(ExcludeSpaceForMarkForTest(kMaxSize + 1)));
+
+ for (int offset = kPageSize; offset < kMaxSize; offset += kPageSize) {
+ // Only the first and last page of a span are in heap map. So for others
+ // tcmalloc will give a general error of invalid pointer.
+ ASSERT_DEATH(TCMallocDoFreeForTest(p + offset),
+ "Attempt to free invalid pointer");
+ }
+ ASSERT_DEATH(TCMallocDoFreeForTest(p + kMaxSize),
+ "Pointer is not pointing to the start of a span");
+}
+
+TEST(TCMallocFreeCheck, DoubleFreeLargeObject) {
+ char* p = reinterpret_cast<char*>(
+ TCMallocDoMallocForTest(ExcludeSpaceForMarkForTest(kMaxSize + 1)));
+ ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p),
+ "Object was not in-use");
+}
+
+
+#ifdef NDEBUG
+TEST(TCMallocFreeCheck, DoubleFreeSmallObject) {
+ for (size_t size = 1;
+ size <= ExcludeSpaceForMarkForTest(kMaxSize);
+ size <<= 1) {
+ char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(size));
+ ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p),
+ "Circular loop in list detected");
+ }
+}
+#else
+TEST(TCMallocFreeCheck, DoubleFreeSmallObject) {
+ size_t size = 1;
+
+ // When the object is small, tcmalloc validation can not distinguish normal
+ // memory corruption or double free, because there's not enough space in
+ // freed objects to keep the mark.
+ for (; size <= ExcludeSpaceForMarkForTest(kMinClassSize); size <<= 1) {
+ char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(size));
+ ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p),
+ "Memory corrupted");
+ }
+
+ for (; size <= ExcludeSpaceForMarkForTest(kMaxSize); size <<= 1) {
+ char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(size));
+ ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p),
+ "Attempt to double free");
+ }
+}
+#endif
+
+int main(int argc, char **argv) {
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/src/base/allocator/type_profiler.cc b/src/base/allocator/type_profiler.cc
new file mode 100644
index 0000000..635fbcf
--- /dev/null
+++ b/src/base/allocator/type_profiler.cc
@@ -0,0 +1,63 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#if defined(TYPE_PROFILING)
+
+#include "base/allocator/type_profiler.h"
+
+#include <assert.h>
+
+namespace {
+
+void* NopIntercept(void* ptr, size_t size, const std::type_info& type) {
+ return ptr;
+}
+
+base::type_profiler::InterceptFunction* g_new_intercept = NopIntercept;
+base::type_profiler::InterceptFunction* g_delete_intercept = NopIntercept;
+
+}
+
+void* __op_new_intercept__(void* ptr,
+ size_t size,
+ const std::type_info& type) {
+ return g_new_intercept(ptr, size, type);
+}
+
+void* __op_delete_intercept__(void* ptr,
+ size_t size,
+ const std::type_info& type) {
+ return g_delete_intercept(ptr, size, type);
+}
+
+namespace base {
+namespace type_profiler {
+
+// static
+void InterceptFunctions::SetFunctions(InterceptFunction* new_intercept,
+ InterceptFunction* delete_intercept) {
+ // Don't use DCHECK, as this file is injected into targets
+ // that do not and should not depend on base/base.gyp:base
+ assert(g_new_intercept == NopIntercept);
+ assert(g_delete_intercept == NopIntercept);
+
+ g_new_intercept = new_intercept;
+ g_delete_intercept = delete_intercept;
+}
+
+// static
+void InterceptFunctions::ResetFunctions() {
+ g_new_intercept = NopIntercept;
+ g_delete_intercept = NopIntercept;
+}
+
+// static
+bool InterceptFunctions::IsAvailable() {
+ return g_new_intercept != NopIntercept || g_delete_intercept != NopIntercept;
+}
+
+} // namespace type_profiler
+} // namespace base
+
+#endif // defined(TYPE_PROFILING)
diff --git a/src/base/allocator/type_profiler.h b/src/base/allocator/type_profiler.h
new file mode 100644
index 0000000..86b5711
--- /dev/null
+++ b/src/base/allocator/type_profiler.h
@@ -0,0 +1,40 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ALLOCATOR_TYPE_PROFILER_H_
+#define BASE_ALLOCATOR_TYPE_PROFILER_H_
+
+#if defined(TYPE_PROFILING)
+
+#include <stddef.h> // for size_t
+#include <typeinfo> // for std::typeinfo
+
+namespace base {
+namespace type_profiler {
+
+typedef void* InterceptFunction(void*, size_t, const std::type_info&);
+
+class InterceptFunctions {
+ public:
+ // It must be called only once in a process while it is in single-thread.
+ // For now, ContentMainRunnerImpl::Initialize is the only supposed caller
+ // of this function except for single-threaded unit tests.
+ static void SetFunctions(InterceptFunction* new_intercept,
+ InterceptFunction* delete_intercept);
+
+ private:
+ friend class TypeProfilerTest;
+
+ // These functions are not thread safe.
+ // They must be used only from single-threaded unit tests.
+ static void ResetFunctions();
+ static bool IsAvailable();
+};
+
+} // namespace type_profiler
+} // namespace base
+
+#endif // defined(TYPE_PROFILING)
+
+#endif // BASE_ALLOCATOR_TYPE_PROFILER_H_
diff --git a/src/base/allocator/type_profiler_control.cc b/src/base/allocator/type_profiler_control.cc
new file mode 100644
index 0000000..6be7984
--- /dev/null
+++ b/src/base/allocator/type_profiler_control.cc
@@ -0,0 +1,38 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/allocator/type_profiler_control.h"
+
+namespace base {
+namespace type_profiler {
+
+namespace {
+
+#if defined(TYPE_PROFILING)
+const bool kTypeProfilingEnabled = true;
+#else
+const bool kTypeProfilingEnabled = false;
+#endif
+
+bool g_enable_intercept = kTypeProfilingEnabled;
+
+} // namespace
+
+// static
+void Controller::Stop() {
+ g_enable_intercept = false;
+}
+
+// static
+bool Controller::IsProfiling() {
+ return kTypeProfilingEnabled && g_enable_intercept;
+}
+
+// static
+void Controller::Restart() {
+ g_enable_intercept = kTypeProfilingEnabled;
+}
+
+} // namespace type_profiler
+} // namespace base
diff --git a/src/base/allocator/type_profiler_control.h b/src/base/allocator/type_profiler_control.h
new file mode 100644
index 0000000..17cf5b6
--- /dev/null
+++ b/src/base/allocator/type_profiler_control.h
@@ -0,0 +1,31 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ALLOCATOR_TYPE_PROFILER_CONTROL_H_
+#define BASE_ALLOCATOR_TYPE_PROFILER_CONTROL_H_
+
+#include "base/gtest_prod_util.h"
+
+namespace base {
+namespace type_profiler {
+
+class Controller {
+ public:
+ static void Stop();
+ static bool IsProfiling();
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(TypeProfilerTest,
+ TestProfileNewWithoutProfiledDelete);
+
+ // It must be used only from allowed unit tests. The following is only
+ // allowed for use in unit tests. Profiling should never be restarted in
+ // regular use.
+ static void Restart();
+};
+
+} // namespace type_profiler
+} // namespace base
+
+#endif // BASE_ALLOCATOR_TYPE_PROFILER_CONTROL_H_
diff --git a/src/base/allocator/type_profiler_map_unittests.cc b/src/base/allocator/type_profiler_map_unittests.cc
new file mode 100644
index 0000000..ff74e11
--- /dev/null
+++ b/src/base/allocator/type_profiler_map_unittests.cc
@@ -0,0 +1,99 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is a unittest set for type_profiler_map in third_party/tcmalloc. It is
+// independent from other tests and executed manually like allocator_unittests
+// since type_profiler_map is a singleton (like TCMalloc's heap-profiler), and
+// it requires RTTI and different compiling/linking options from others.
+
+#if defined(TYPE_PROFILING)
+
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/tcmalloc/chromium/src/gperftools/type_profiler_map.h"
+
+namespace base {
+namespace type_profiler {
+
+static const void* const g_const_null = static_cast<const void*>(NULL);
+
+TEST(TypeProfilerMapTest, NormalOperation) {
+ // Allocate an object just to get a valid address.
+ // This 'new' is not profiled by type_profiler.
+ scoped_ptr<int> dummy(new int(48));
+ const std::type_info* type;
+
+ type = LookupType(dummy.get());
+ EXPECT_EQ(g_const_null, type);
+
+ InsertType(dummy.get(), 12, typeid(int));
+ type = LookupType(dummy.get());
+ ASSERT_NE(g_const_null, type);
+ EXPECT_STREQ(typeid(int).name(), type->name());
+
+ EraseType(dummy.get());
+ type = LookupType(dummy.get());
+ EXPECT_EQ(g_const_null, type);
+}
+
+TEST(TypeProfilerMapTest, EraseWithoutInsert) {
+ scoped_ptr<int> dummy(new int(48));
+ const std::type_info* type;
+
+ for (int i = 0; i < 10; ++i) {
+ EraseType(dummy.get());
+ type = LookupType(dummy.get());
+ EXPECT_EQ(g_const_null, type);
+ }
+}
+
+TEST(TypeProfilerMapTest, InsertThenMultipleErase) {
+ scoped_ptr<int> dummy(new int(48));
+ const std::type_info* type;
+
+ InsertType(dummy.get(), 12, typeid(int));
+ type = LookupType(dummy.get());
+ ASSERT_NE(g_const_null, type);
+ EXPECT_STREQ(typeid(int).name(), type->name());
+
+ for (int i = 0; i < 10; ++i) {
+ EraseType(dummy.get());
+ type = LookupType(dummy.get());
+ EXPECT_EQ(g_const_null, type);
+ }
+}
+
+TEST(TypeProfilerMapTest, MultipleInsertWithoutErase) {
+ scoped_ptr<int> dummy(new int(48));
+ const std::type_info* type;
+
+ InsertType(dummy.get(), 12, typeid(int));
+ type = LookupType(dummy.get());
+ ASSERT_NE(g_const_null, type);
+ EXPECT_STREQ(typeid(int).name(), type->name());
+
+ InsertType(dummy.get(), 5, typeid(char));
+ type = LookupType(dummy.get());
+ ASSERT_NE(g_const_null, type);
+ EXPECT_STREQ(typeid(char).name(), type->name());
+
+ InsertType(dummy.get(), 129, typeid(long));
+ type = LookupType(dummy.get());
+ ASSERT_NE(g_const_null, type);
+ EXPECT_STREQ(typeid(long).name(), type->name());
+
+ EraseType(dummy.get());
+ type = LookupType(dummy.get());
+ EXPECT_EQ(g_const_null, type);
+}
+
+} // namespace type_profiler
+} // namespace base
+
+int main(int argc, char** argv) {
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
+
+#endif // defined(TYPE_PROFILING)
diff --git a/src/base/allocator/type_profiler_tcmalloc.cc b/src/base/allocator/type_profiler_tcmalloc.cc
new file mode 100644
index 0000000..e5e10e0
--- /dev/null
+++ b/src/base/allocator/type_profiler_tcmalloc.cc
@@ -0,0 +1,37 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#if defined(TYPE_PROFILING)
+
+#include "base/allocator/type_profiler_tcmalloc.h"
+
+#include "base/allocator/type_profiler_control.h"
+#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h"
+#include "third_party/tcmalloc/chromium/src/gperftools/type_profiler_map.h"
+
+namespace base {
+namespace type_profiler {
+
+void* NewInterceptForTCMalloc(void* ptr,
+ size_t size,
+ const std::type_info& type) {
+ if (Controller::IsProfiling())
+ InsertType(ptr, size, type);
+
+ return ptr;
+}
+
+void* DeleteInterceptForTCMalloc(void* ptr,
+ size_t size,
+ const std::type_info& type) {
+ if (Controller::IsProfiling())
+ EraseType(ptr);
+
+ return ptr;
+}
+
+} // namespace type_profiler
+} // namespace base
+
+#endif // defined(TYPE_PROFILING)
diff --git a/src/base/allocator/type_profiler_tcmalloc.h b/src/base/allocator/type_profiler_tcmalloc.h
new file mode 100644
index 0000000..ac55995
--- /dev/null
+++ b/src/base/allocator/type_profiler_tcmalloc.h
@@ -0,0 +1,29 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ALLOCATOR_TYPE_PROFILER_TCMALLOC_H_
+#define BASE_ALLOCATOR_TYPE_PROFILER_TCMALLOC_H_
+
+#if defined(TYPE_PROFILING)
+
+#include <cstddef> // for size_t
+#include <typeinfo> // for std::type_info
+
+namespace base {
+namespace type_profiler {
+
+void* NewInterceptForTCMalloc(void* ptr,
+ size_t size,
+ const std::type_info& type);
+
+void* DeleteInterceptForTCMalloc(void* ptr,
+ size_t size,
+ const std::type_info& type);
+
+} // namespace type_profiler
+} // namespace base
+
+#endif // defined(TYPE_PROFILING)
+
+#endif // BASE_ALLOCATOR_TYPE_PROFILER_TCMALLOC_H_
diff --git a/src/base/allocator/type_profiler_unittests.cc b/src/base/allocator/type_profiler_unittests.cc
new file mode 100644
index 0000000..16af86d
--- /dev/null
+++ b/src/base/allocator/type_profiler_unittests.cc
@@ -0,0 +1,189 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is a unittest set for type_profiler. It is independent from other
+// tests and executed manually like allocator_unittests since type_profiler_map
+// used in type_profiler is a singleton (like TCMalloc's heap-profiler), and
+// it requires RTTI and different compiling/linking options from others
+//
+// It tests that the profiler doesn't fail in suspicous cases. For example,
+// 'new' is not profiled, but 'delete' for the created object is profiled.
+
+#if defined(TYPE_PROFILING)
+
+#include "base/allocator/type_profiler.h"
+#include "base/allocator/type_profiler_control.h"
+#include "base/allocator/type_profiler_tcmalloc.h"
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/tcmalloc/chromium/src/gperftools/type_profiler_map.h"
+
+namespace base {
+namespace type_profiler {
+
+class TypeProfilerTest : public testing::Test {
+ public:
+ TypeProfilerTest() {}
+
+ void SetInterceptFunctions() {
+ InterceptFunctions::SetFunctions(NewInterceptForTCMalloc,
+ DeleteInterceptForTCMalloc);
+ }
+
+ void ResetInterceptFunctions() {
+ InterceptFunctions::ResetFunctions();
+ }
+
+ void SetUp() {
+ SetInterceptFunctions();
+ }
+
+ void TearDown() {
+ ResetInterceptFunctions();
+ }
+
+ protected:
+ static const size_t kDummyArraySize;
+ static const void* const kConstNull;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TypeProfilerTest);
+};
+
+const size_t TypeProfilerTest::kDummyArraySize = 10;
+const void* const TypeProfilerTest::kConstNull = static_cast<const void*>(NULL);
+
+TEST_F(TypeProfilerTest, TestNormalProfiling) {
+ int* dummy = new int(48);
+ const std::type_info* type;
+
+ type = LookupType(dummy);
+ ASSERT_NE(kConstNull, type);
+ EXPECT_STREQ(typeid(int).name(), type->name());
+ delete dummy;
+
+ type = LookupType(dummy);
+ EXPECT_EQ(kConstNull, type);
+}
+
+TEST_F(TypeProfilerTest, TestNormalArrayProfiling) {
+ int* dummy = new int[kDummyArraySize];
+ const std::type_info* type;
+
+ type = LookupType(dummy);
+ ASSERT_NE(kConstNull, type);
+ // For an array, the profiler remembers its base type.
+ EXPECT_STREQ(typeid(int).name(), type->name());
+ delete[] dummy;
+
+ type = LookupType(dummy);
+ EXPECT_EQ(kConstNull, type);
+}
+
+TEST_F(TypeProfilerTest, TestRepeatedNewAndDelete) {
+ int *dummy[kDummyArraySize];
+ const std::type_info* type;
+ for (int i = 0; i < kDummyArraySize; ++i)
+ dummy[i] = new int(i);
+
+ for (int i = 0; i < kDummyArraySize; ++i) {
+ type = LookupType(dummy[i]);
+ ASSERT_NE(kConstNull, type);
+ EXPECT_STREQ(typeid(int).name(), type->name());
+ }
+
+ for (int i = 0; i < kDummyArraySize; ++i) {
+ delete dummy[i];
+ type = LookupType(dummy[i]);
+ ASSERT_EQ(kConstNull, type);
+ }
+}
+
+TEST_F(TypeProfilerTest, TestMultipleNewWithDroppingDelete) {
+ static const size_t large_size = 256 * 1024;
+
+ char* dummy_char = new char[large_size / sizeof(*dummy_char)];
+ const std::type_info* type;
+
+ type = LookupType(dummy_char);
+ ASSERT_NE(kConstNull, type);
+ EXPECT_STREQ(typeid(char).name(), type->name());
+
+ // Call "::operator delete" directly to drop __op_delete_intercept__.
+ ::operator delete[](dummy_char);
+
+ type = LookupType(dummy_char);
+ ASSERT_NE(kConstNull, type);
+ EXPECT_STREQ(typeid(char).name(), type->name());
+
+ // Allocates a little different size.
+ int* dummy_int = new int[large_size / sizeof(*dummy_int) - 1];
+
+ // We expect that tcmalloc returns the same address for these large (over 32k)
+ // allocation calls. It usually happens, but maybe probablistic.
+ ASSERT_EQ(static_cast<void*>(dummy_char), static_cast<void*>(dummy_int)) <<
+ "two new (malloc) calls didn't return the same address; retry it.";
+
+ type = LookupType(dummy_int);
+ ASSERT_NE(kConstNull, type);
+ EXPECT_STREQ(typeid(int).name(), type->name());
+
+ delete[] dummy_int;
+
+ type = LookupType(dummy_int);
+ EXPECT_EQ(kConstNull, type);
+}
+
+TEST_F(TypeProfilerTest, TestProfileDeleteWithoutProfiledNew) {
+ // 'dummy' should be new'ed in this test before intercept functions are set.
+ ResetInterceptFunctions();
+
+ int* dummy = new int(48);
+ const std::type_info* type;
+
+ // Set intercept functions again after 'dummy' is new'ed.
+ SetInterceptFunctions();
+
+ delete dummy;
+
+ type = LookupType(dummy);
+ EXPECT_EQ(kConstNull, type);
+
+ ResetInterceptFunctions();
+}
+
+TEST_F(TypeProfilerTest, TestProfileNewWithoutProfiledDelete) {
+ int* dummy = new int(48);
+ const std::type_info* type;
+
+ EXPECT_TRUE(Controller::IsProfiling());
+
+ // Stop profiling before deleting 'dummy'.
+ Controller::Stop();
+ EXPECT_FALSE(Controller::IsProfiling());
+
+ delete dummy;
+
+ // NOTE: We accept that a profile entry remains when a profiled object is
+ // deleted after Controller::Stop().
+ type = LookupType(dummy);
+ ASSERT_NE(kConstNull, type);
+ EXPECT_STREQ(typeid(int).name(), type->name());
+
+ Controller::Restart();
+ EXPECT_TRUE(Controller::IsProfiling());
+
+ // Remove manually since 'dummy' is not removed from type_profiler_map.
+ EraseType(dummy);
+}
+
+} // namespace type_profiler
+} // namespace base
+
+int main(int argc, char** argv) {
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
+
+#endif // defined(TYPE_PROFILING)
diff --git a/src/base/allocator/unittest_utils.cc b/src/base/allocator/unittest_utils.cc
new file mode 100644
index 0000000..130ba15
--- /dev/null
+++ b/src/base/allocator/unittest_utils.cc
@@ -0,0 +1,18 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// The unittests need a this in order to link up without pulling in tons
+// of other libraries
+
+#include <config.h>
+
+inline int snprintf(char* buffer, size_t count, const char* format, ...) {
+ int result;
+ va_list args;
+ va_start(args, format);
+ result = _vsnprintf(buffer, count, format, args);
+ va_end(args);
+ return result;
+}
+
diff --git a/src/base/allocator/win_allocator.cc b/src/base/allocator/win_allocator.cc
new file mode 100644
index 0000000..899b867
--- /dev/null
+++ b/src/base/allocator/win_allocator.cc
@@ -0,0 +1,73 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is a simple allocator based on the windows heap.
+
+extern "C" {
+
+HANDLE win_heap;
+
+bool win_heap_init(bool use_lfh) {
+ win_heap = HeapCreate(0, 0, 0);
+ if (win_heap == NULL)
+ return false;
+
+ if (use_lfh) {
+ ULONG enable_lfh = 2;
+ HeapSetInformation(win_heap, HeapCompatibilityInformation,
+ &enable_lfh, sizeof(enable_lfh));
+ // NOTE: Setting LFH may fail. Vista already has it enabled.
+ // And under the debugger, it won't use LFH. So we
+ // ignore any errors.
+ }
+
+ return true;
+}
+
+void* win_heap_malloc(size_t size) {
+ return HeapAlloc(win_heap, 0, size);
+}
+
+void win_heap_free(void* size) {
+ HeapFree(win_heap, 0, size);
+}
+
+void* win_heap_realloc(void* ptr, size_t size) {
+ if (!ptr)
+ return win_heap_malloc(size);
+ if (!size) {
+ win_heap_free(ptr);
+ return NULL;
+ }
+ return HeapReAlloc(win_heap, 0, ptr, size);
+}
+
+size_t win_heap_msize(void* ptr) {
+ return HeapSize(win_heap, 0, ptr);
+}
+
+void* win_heap_memalign(size_t alignment, size_t size) {
+ // Reserve enough space to ensure we can align and set aligned_ptr[-1] to the
+ // original allocation for use with win_heap_memalign_free() later.
+ size_t allocation_size = size + (alignment - 1) + sizeof(void*);
+
+ // Check for overflow. Alignment and size are checked in allocator_shim.
+ DCHECK_LT(size, allocation_size);
+ DCHECK_LT(alignment, allocation_size);
+
+ void* ptr = win_heap_malloc(allocation_size);
+ char* aligned_ptr = static_cast<char*>(ptr) + sizeof(void*);
+ aligned_ptr +=
+ alignment - reinterpret_cast<uintptr_t>(aligned_ptr) & (alignment - 1);
+
+ reinterpret_cast<void**>(aligned_ptr)[-1] = ptr;
+ return aligned_ptr;
+}
+
+void win_heap_memalign_free(void* ptr) {
+ if (ptr)
+ win_heap_free(static_cast<void**>(ptr)[-1]);
+}
+
+} // extern "C"
diff --git a/src/base/android/base_jni_registrar.cc b/src/base/android/base_jni_registrar.cc
new file mode 100644
index 0000000..2395d98
--- /dev/null
+++ b/src/base/android/base_jni_registrar.cc
@@ -0,0 +1,37 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/base_jni_registrar.h"
+
+#include "base/basictypes.h"
+#include "base/android/build_info.h"
+#include "base/android/cpu_features.h"
+#include "base/android/jni_android.h"
+#include "base/android/jni_registrar.h"
+#include "base/android/locale_utils.h"
+#include "base/android/path_service_android.h"
+#include "base/android/path_utils.h"
+#include "base/message_pump_android.h"
+#include "base/system_monitor/system_monitor_android.h"
+
+namespace base {
+namespace android {
+
+static RegistrationMethod kBaseRegisteredMethods[] = {
+ { "BuildInfo", base::android::BuildInfo::RegisterBindings },
+ { "CpuFeatures", base::android::RegisterCpuFeatures },
+ { "LocaleUtils", base::android::RegisterLocaleUtils },
+ { "PathService", base::android::RegisterPathService },
+ { "PathUtils", base::android::RegisterPathUtils },
+ { "SystemMessageHandler", base::MessagePumpForUI::RegisterBindings },
+ { "SystemMonitor", base::RegisterSystemMonitor },
+};
+
+bool RegisterJni(JNIEnv* env) {
+ return RegisterNativeMethods(env, kBaseRegisteredMethods,
+ arraysize(kBaseRegisteredMethods));
+}
+
+} // namespace android
+} // namespace base
diff --git a/src/base/android/base_jni_registrar.h b/src/base/android/base_jni_registrar.h
new file mode 100644
index 0000000..fdaf5f2
--- /dev/null
+++ b/src/base/android/base_jni_registrar.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_BASE_JNI_REGISTRAR_H_
+#define BASE_ANDROID_BASE_JNI_REGISTRAR_H_
+
+#include <jni.h>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace android {
+
+// Register all JNI bindings necessary for base.
+BASE_EXPORT bool RegisterJni(JNIEnv* env);
+
+} // namespace android
+} // namespace base
+
+#endif // BASE_ANDROID_BASE_JNI_REGISTRAR_H_
diff --git a/src/base/android/build_info.cc b/src/base/android/build_info.cc
new file mode 100644
index 0000000..cdde6a9
--- /dev/null
+++ b/src/base/android/build_info.cc
@@ -0,0 +1,78 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/build_info.h"
+
+#include <string>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "jni/BuildInfo_jni.h"
+
+namespace {
+
+// The caller takes ownership of the returned const char*.
+const char* StrDupJString(const base::android::JavaRef<jstring>& java_string) {
+ std::string str = ConvertJavaStringToUTF8(java_string);
+ return strdup(str.c_str());
+}
+
+} // namespace
+
+namespace base {
+namespace android {
+
+struct BuildInfoSingletonTraits {
+ static BuildInfo* New() {
+ return new BuildInfo(AttachCurrentThread());
+ }
+
+ static void Delete(BuildInfo* x) {
+ // We're leaking this type, see kRegisterAtExit.
+ NOTREACHED();
+ }
+
+ static const bool kRegisterAtExit = false;
+ static const bool kAllowedToAccessOnNonjoinableThread = true;
+};
+
+BuildInfo::BuildInfo(JNIEnv* env)
+ : device_(StrDupJString(Java_BuildInfo_getDevice(env))),
+ model_(StrDupJString(Java_BuildInfo_getDeviceModel(env))),
+ brand_(StrDupJString(Java_BuildInfo_getBrand(env))),
+ android_build_id_(StrDupJString(Java_BuildInfo_getAndroidBuildId(env))),
+ android_build_fp_(StrDupJString(
+ Java_BuildInfo_getAndroidBuildFingerprint(env))),
+ package_version_code_(StrDupJString(Java_BuildInfo_getPackageVersionCode(
+ env, GetApplicationContext()))),
+ package_version_name_(StrDupJString(Java_BuildInfo_getPackageVersionName(
+ env, GetApplicationContext()))),
+ package_label_(StrDupJString(Java_BuildInfo_getPackageLabel(
+ env, GetApplicationContext()))),
+ package_name_(StrDupJString(Java_BuildInfo_getPackageName(
+ env, GetApplicationContext()))),
+ sdk_int_(Java_BuildInfo_getSdkInt(env)),
+ java_exception_info_(NULL) {
+}
+
+// static
+BuildInfo* BuildInfo::GetInstance() {
+ return Singleton<BuildInfo, BuildInfoSingletonTraits >::get();
+}
+
+void BuildInfo::set_java_exception_info(const std::string& info) {
+ DCHECK(!java_exception_info_) << "info should be set only once.";
+ java_exception_info_ = strndup(info.c_str(), 1024);
+}
+
+// static
+bool BuildInfo::RegisterBindings(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+} // namespace android
+} // namespace base
diff --git a/src/base/android/build_info.h b/src/base/android/build_info.h
new file mode 100644
index 0000000..6273d3e
--- /dev/null
+++ b/src/base/android/build_info.h
@@ -0,0 +1,114 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_BUILD_INFO_H_
+#define BASE_ANDROID_BUILD_INFO_H_
+
+#include <jni.h>
+
+#include <string>
+
+#include "base/memory/singleton.h"
+
+namespace base {
+namespace android {
+
+// BuildInfo is a singleton class that stores android build and device
+// information. It will be called from Android specific code and gets used
+// primarily in crash reporting.
+
+// It is also used to store the last java exception seen during JNI.
+// TODO(nileshagrawal): Find a better place to store this info.
+class BuildInfo {
+ public:
+
+ ~BuildInfo() {}
+
+ // Static factory method for getting the singleton BuildInfo instance.
+ // Note that ownership is not conferred on the caller and the BuildInfo in
+ // question isn't actually freed until shutdown. This is ok because there
+ // should only be one instance of BuildInfo ever created.
+ static BuildInfo* GetInstance();
+
+ // Const char* is used instead of std::strings because these values must be
+ // available even if the process is in a crash state. Sadly
+ // std::string.c_str() doesn't guarantee that memory won't be allocated when
+ // it is called.
+ const char* device() const {
+ return device_;
+ }
+
+ const char* model() const {
+ return model_;
+ }
+
+ const char* brand() const {
+ return brand_;
+ }
+
+ const char* android_build_id() const {
+ return android_build_id_;
+ }
+
+ const char* android_build_fp() const {
+ return android_build_fp_;
+ }
+
+ const char* package_version_code() const {
+ return package_version_code_;
+ }
+
+ const char* package_version_name() const {
+ return package_version_name_;
+ }
+
+ const char* package_label() const {
+ return package_label_;
+ }
+
+ const char* package_name() const {
+ return package_name_;
+ }
+
+ int sdk_int() const {
+ return sdk_int_;
+ }
+
+ const char* java_exception_info() const {
+ return java_exception_info_;
+ }
+
+ void set_java_exception_info(const std::string& info);
+
+ static bool RegisterBindings(JNIEnv* env);
+
+ private:
+ friend struct BuildInfoSingletonTraits;
+
+ explicit BuildInfo(JNIEnv* env);
+
+ // Const char* is used instead of std::strings because these values must be
+ // available even if the process is in a crash state. Sadly
+ // std::string.c_str() doesn't guarantee that memory won't be allocated when
+ // it is called.
+ const char* const device_;
+ const char* const model_;
+ const char* const brand_;
+ const char* const android_build_id_;
+ const char* const android_build_fp_;
+ const char* const package_version_code_;
+ const char* const package_version_name_;
+ const char* const package_label_;
+ const char* const package_name_;
+ const int sdk_int_;
+ // This is set via set_java_exception_info, not at constructor time.
+ const char* java_exception_info_;
+
+ DISALLOW_COPY_AND_ASSIGN(BuildInfo);
+};
+
+} // namespace android
+} // namespace base
+
+#endif // BASE_ANDROID_BUILD_INFO_H_
diff --git a/src/base/android/cpu_features.cc b/src/base/android/cpu_features.cc
new file mode 100644
index 0000000..6a18695
--- /dev/null
+++ b/src/base/android/cpu_features.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <cpu-features.h>
+
+#include "base/android/jni_android.h"
+#include "jni/CpuFeatures_jni.h"
+
+namespace base {
+namespace android {
+
+jint GetCoreCount(JNIEnv*, jclass) {
+ return android_getCpuCount();
+}
+
+jlong GetCpuFeatures(JNIEnv*, jclass) {
+ return android_getCpuFeatures();
+}
+
+bool RegisterCpuFeatures(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+} // namespace android
+} // namespace base
diff --git a/src/base/android/cpu_features.h b/src/base/android/cpu_features.h
new file mode 100644
index 0000000..0a27822
--- /dev/null
+++ b/src/base/android/cpu_features.h
@@ -0,0 +1,18 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_CPU_FEATURES_H_
+#define BASE_ANDROID_CPU_FEATURES_H_
+
+#include <jni.h>
+
+namespace base {
+namespace android {
+
+bool RegisterCpuFeatures(JNIEnv* env);
+
+} // namespace android
+} // namespace base
+
+#endif // BASE_ANDROID_CPU_FEATURES_H_
diff --git a/src/base/android/java/src/org/chromium/base/AccessedByNative.java b/src/base/android/java/src/org/chromium/base/AccessedByNative.java
new file mode 100644
index 0000000..8248cc6
--- /dev/null
+++ b/src/base/android/java/src/org/chromium/base/AccessedByNative.java
@@ -0,0 +1,20 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @AccessedByNative is used to ensure proguard will keep this field, since it's
+ * only accessed by native.
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AccessedByNative {
+ public String value() default "";
+}
diff --git a/src/base/android/java/src/org/chromium/base/ActivityStatus.java b/src/base/android/java/src/org/chromium/base/ActivityStatus.java
new file mode 100644
index 0000000..e728870
--- /dev/null
+++ b/src/base/android/java/src/org/chromium/base/ActivityStatus.java
@@ -0,0 +1,99 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.app.Activity;
+import android.os.Looper;
+
+import java.util.ArrayList;
+
+/**
+ * Provides information about the parent activity's status.
+ */
+public class ActivityStatus {
+
+ // Constants matching activity states reported to StateListener.onStateChange
+ public static final int CREATED = 1;
+ public static final int STARTED = 2;
+ public static final int RESUMED = 3;
+ public static final int PAUSED = 4;
+ public static final int STOPPED = 5;
+ public static final int DESTROYED = 6;
+
+ // Current main activity, or null if none.
+ private static Activity sActivity;
+
+ // Current main activity's state. This can be set even if sActivity is null, to simplify unit
+ // testing.
+ private static int sActivityState;
+
+ private static final ArrayList<StateListener> sStateListeners = new ArrayList<StateListener>();
+
+ // Use this interface to listen to all state changes.
+ public interface StateListener {
+ /**
+ * Called when the activity's state changes.
+ * @param newState New activity state.
+ */
+ public void onActivityStateChange(int newState);
+ }
+
+ private ActivityStatus() {}
+
+ /**
+ * Must be called by the main activity when it changes state.
+ * @param activity Current activity.
+ * @param newState New state value.
+ */
+ public static void onStateChange(Activity activity, int newState) {
+ if (newState == CREATED) {
+ sActivity = activity;
+ }
+ sActivityState = newState;
+ for (StateListener listener : sStateListeners) {
+ listener.onActivityStateChange(newState);
+ }
+ if (newState == DESTROYED) {
+ sActivity = null;
+ }
+ }
+
+ /**
+ * Indicates that the parent activity is currently paused.
+ */
+ public static boolean isPaused() {
+ return sActivityState == PAUSED;
+ }
+
+ /**
+ * Returns the current main application activity.
+ */
+ public static Activity getActivity() {
+ return sActivity;
+ }
+
+ /**
+ * Returns the current main application activity's state.
+ */
+ public static int getState() {
+ return sActivityState;
+ }
+
+ /**
+ * Registers the given listener to receive activity state changes.
+ * @param listener Listener to receive state changes.
+ */
+ public static void registerStateListener(StateListener listener) {
+ sStateListeners.add(listener);
+ }
+
+ /**
+ * Unregisters the given listener from receiving activity state changes.
+ * @param listener Listener that doesn't want to receive state changes.
+ */
+ public static void unregisterStateListener(StateListener listener) {
+ sStateListeners.remove(listener);
+ }
+}
diff --git a/src/base/android/java/src/org/chromium/base/BuildInfo.java b/src/base/android/java/src/org/chromium/base/BuildInfo.java
new file mode 100644
index 0000000..2314051
--- /dev/null
+++ b/src/base/android/java/src/org/chromium/base/BuildInfo.java
@@ -0,0 +1,114 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Build;
+import android.util.Log;
+
+import org.chromium.base.CalledByNative;
+
+/**
+ * BuildInfo is a utility class providing easy access to {@link PackageInfo}
+ * information. This is primarly of use for accessesing package information
+ * from native code.
+ */
+public class BuildInfo {
+ private static final String TAG = "BuildInfo";
+ private static final int MAX_FINGERPRINT_LENGTH = 128;
+
+ /**
+ * BuildInfo is a static utility class and therefore shouldn't be
+ * instantiated.
+ */
+ private BuildInfo() {
+ }
+
+ @CalledByNative
+ public static String getDevice() {
+ return Build.DEVICE;
+ }
+
+ @CalledByNative
+ public static String getBrand() {
+ return Build.BRAND;
+ }
+
+ @CalledByNative
+ public static String getAndroidBuildId() {
+ return Build.ID;
+ }
+
+ /**
+ * @return The build fingerprint for the current Android install. The value is truncated to a
+ * 128 characters as this is used for crash and UMA reporting, which should avoid huge
+ * strings.
+ */
+ @CalledByNative
+ public static String getAndroidBuildFingerprint() {
+ return Build.FINGERPRINT.substring(
+ 0, Math.min(Build.FINGERPRINT.length(), MAX_FINGERPRINT_LENGTH));
+ }
+
+ @CalledByNative
+ public static String getDeviceModel() {
+ return Build.MODEL;
+ }
+
+ @CalledByNative
+ public static String getPackageVersionCode(Context context) {
+ String msg = "versionCode not available.";
+ try {
+ PackageManager pm = context.getPackageManager();
+ PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
+ msg = "" + pi.versionCode;
+ } catch (NameNotFoundException e) {
+ Log.d(TAG, msg);
+ }
+ return msg;
+
+ }
+
+ @CalledByNative
+ public static String getPackageVersionName(Context context) {
+ String msg = "versionName not available";
+ try {
+ PackageManager pm = context.getPackageManager();
+ PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
+ msg = pi.versionName;
+ } catch (NameNotFoundException e) {
+ Log.d(TAG, msg);
+ }
+ return msg;
+ }
+
+ @CalledByNative
+ public static String getPackageLabel(Context context) {
+ try {
+ PackageManager packageManager = context.getPackageManager();
+ ApplicationInfo appInfo = packageManager.getApplicationInfo(context.getPackageName(),
+ PackageManager.GET_META_DATA);
+ CharSequence label = packageManager.getApplicationLabel(appInfo);
+ return label != null ? label.toString() : "";
+ } catch (NameNotFoundException e) {
+ return "";
+ }
+ }
+
+ @CalledByNative
+ public static String getPackageName(Context context) {
+ String packageName = context != null ? context.getPackageName() : null;
+ return packageName != null ? packageName : "";
+ }
+
+ @CalledByNative
+ public static int getSdkInt() {
+ return Build.VERSION.SDK_INT;
+ }
+}
diff --git a/src/base/android/java/src/org/chromium/base/CalledByNative.java b/src/base/android/java/src/org/chromium/base/CalledByNative.java
new file mode 100644
index 0000000..8d3dcad
--- /dev/null
+++ b/src/base/android/java/src/org/chromium/base/CalledByNative.java
@@ -0,0 +1,23 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @CalledByNative is used by the JNI generator to create the necessary JNI
+ * bindings and expose this method to native code.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface CalledByNative {
+ /*
+ * If present, tells which inner class the method belongs to.
+ */
+ public String value() default "";
+}
diff --git a/src/base/android/java/src/org/chromium/base/CalledByNativeUnchecked.java b/src/base/android/java/src/org/chromium/base/CalledByNativeUnchecked.java
new file mode 100644
index 0000000..cc264a2
--- /dev/null
+++ b/src/base/android/java/src/org/chromium/base/CalledByNativeUnchecked.java
@@ -0,0 +1,27 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @CalledByNativeUnchecked is used to generate JNI bindings that do not check for exceptions.
+ * It only makes sense to use this annotation on methods that declare a throws... spec.
+ * However, note that the exception received native side maybe an 'unchecked' (RuntimeExpception)
+ * such as NullPointerException, so the native code should differentiate these cases.
+ * Usage of this should be very rare; where possible handle exceptions in the Java side and use a
+ * return value to indicate success / failure.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface CalledByNativeUnchecked {
+ /*
+ * If present, tells which inner class the method belongs to.
+ */
+ public String value() default "";
+}
diff --git a/src/base/android/java/src/org/chromium/base/ChromiumActivity.java b/src/base/android/java/src/org/chromium/base/ChromiumActivity.java
new file mode 100644
index 0000000..65f5ce9
--- /dev/null
+++ b/src/base/android/java/src/org/chromium/base/ChromiumActivity.java
@@ -0,0 +1,49 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+// All Chromium main activities should extend this class. This allows various sub-systems to
+// properly react to activity state changes.
+public class ChromiumActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstance) {
+ super.onCreate(savedInstance);
+ ActivityStatus.onStateChange(this, ActivityStatus.CREATED);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ ActivityStatus.onStateChange(this, ActivityStatus.STARTED);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ ActivityStatus.onStateChange(this, ActivityStatus.RESUMED);
+ }
+
+ @Override
+ protected void onPause() {
+ ActivityStatus.onStateChange(this, ActivityStatus.PAUSED);
+ super.onPause();
+ }
+
+ @Override
+ protected void onStop() {
+ ActivityStatus.onStateChange(this, ActivityStatus.STOPPED);
+ super.onStop();
+ }
+
+ @Override
+ protected void onDestroy() {
+ ActivityStatus.onStateChange(this, ActivityStatus.DESTROYED);
+ super.onDestroy();
+ }
+}
diff --git a/src/base/android/java/src/org/chromium/base/CpuFeatures.java b/src/base/android/java/src/org/chromium/base/CpuFeatures.java
new file mode 100644
index 0000000..f298fb1
--- /dev/null
+++ b/src/base/android/java/src/org/chromium/base/CpuFeatures.java
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+// The only purpose of this class is to allow sending CPU properties
+// from the browser process to sandboxed renderer processes. This is
+// needed because sandboxed processes cannot, on ARM, query the kernel
+// about the CPU's properties by parsing /proc, so this operation must
+// be performed in the browser process, and the result passed to
+// renderer ones.
+//
+// For more context, see http://crbug.com/164154
+//
+// Technically, this is a wrapper around the native NDK cpufeatures
+// library. The exact CPU features bits are never used in Java so
+// there is no point in duplicating their definitions here.
+//
+@JNINamespace("base::android")
+public abstract class CpuFeatures {
+ /**
+ * Return the number of CPU Cores on the device.
+ */
+ public static int getCount() {
+ return nativeGetCoreCount();
+ }
+
+ /**
+ * Return the CPU feature mask.
+ * This is a 64-bit integer that corresponds to the CPU's features.
+ * The value comes directly from android_getCpuFeatures().
+ */
+ public static long getMask() {
+ return nativeGetCpuFeatures();
+ }
+
+ private static native int nativeGetCoreCount();
+ private static native long nativeGetCpuFeatures();
+}
diff --git a/src/base/android/java/src/org/chromium/base/JNINamespace.java b/src/base/android/java/src/org/chromium/base/JNINamespace.java
new file mode 100644
index 0000000..cfffc91
--- /dev/null
+++ b/src/base/android/java/src/org/chromium/base/JNINamespace.java
@@ -0,0 +1,20 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @JNINamespace is used by the JNI generator to create the necessary JNI
+ * bindings and expose this method to native code using the specified namespace.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface JNINamespace {
+ public String value();
+}
diff --git a/src/base/android/java/src/org/chromium/base/LocaleUtils.java b/src/base/android/java/src/org/chromium/base/LocaleUtils.java
new file mode 100644
index 0000000..6bca1f7
--- /dev/null
+++ b/src/base/android/java/src/org/chromium/base/LocaleUtils.java
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import java.util.Locale;
+
+/**
+ * This class provides the locale related methods for the native library.
+ */
+class LocaleUtils {
+
+ private LocaleUtils() { /* cannot be instantiated */ }
+
+ /**
+ * @return the default locale.
+ */
+ @CalledByNative
+ public static String getDefaultLocale() {
+ Locale locale = Locale.getDefault();
+ String language = locale.getLanguage();
+ String country = locale.getCountry();
+ return country.isEmpty() ? language : language + "-" + country;
+ }
+}
diff --git a/src/base/android/java/src/org/chromium/base/NativeClassQualifiedName.java b/src/base/android/java/src/org/chromium/base/NativeClassQualifiedName.java
new file mode 100644
index 0000000..309169b
--- /dev/null
+++ b/src/base/android/java/src/org/chromium/base/NativeClassQualifiedName.java
@@ -0,0 +1,25 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @NativeClassQualifiedName is used by the JNI generator to create the necessary JNI
+ * bindings to call into the specified native class name.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface NativeClassQualifiedName {
+ /*
+ * Tells which native class the method is going to be bound to.
+ * The first parameter of the annotated method must be an int nativePtr pointing to
+ * an instance of this class.
+ */
+ public String value();
+}
diff --git a/src/base/android/java/src/org/chromium/base/PathService.java b/src/base/android/java/src/org/chromium/base/PathService.java
new file mode 100644
index 0000000..dfda736
--- /dev/null
+++ b/src/base/android/java/src/org/chromium/base/PathService.java
@@ -0,0 +1,24 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+/**
+ * This class provides java side access to the native PathService.
+ */
+@JNINamespace("base::android")
+public abstract class PathService {
+
+ // Must match the value of DIR_MODULE in base/base_paths.h!
+ public static final int DIR_MODULE = 3;
+
+ // Prevent instantiation.
+ private PathService() {}
+
+ public static void override(int what, String path) {
+ nativeOverride(what, path);
+ }
+
+ private static native void nativeOverride(int what, String path);
+}
diff --git a/src/base/android/java/src/org/chromium/base/PathUtils.java b/src/base/android/java/src/org/chromium/base/PathUtils.java
new file mode 100644
index 0000000..c3503a4
--- /dev/null
+++ b/src/base/android/java/src/org/chromium/base/PathUtils.java
@@ -0,0 +1,85 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.os.Environment;
+
+/**
+ * This class provides the path related methods for the native library.
+ */
+public abstract class PathUtils {
+
+ private static String sDataDirectorySuffix;
+
+ // Prevent instantiation.
+ private PathUtils() {}
+
+ /**
+ * Sets the suffix that should be used for the directory where private data is to be stored
+ * by the application.
+ * @param suffix The private data directory suffix.
+ * @see Context#getDir(String, int)
+ */
+ public static void setPrivateDataDirectorySuffix(String suffix) {
+ sDataDirectorySuffix = suffix;
+ }
+
+ /**
+ * @return the private directory that is used to store application data.
+ */
+ @CalledByNative
+ public static String getDataDirectory(Context appContext) {
+ if (sDataDirectorySuffix == null) {
+ throw new IllegalStateException(
+ "setDataDirectorySuffix must be called before getDataDirectory");
+ }
+ return appContext.getDir(sDataDirectorySuffix, Context.MODE_PRIVATE).getPath();
+ }
+
+ /**
+ * @return the cache directory.
+ */
+ @SuppressWarnings("unused")
+ @CalledByNative
+ private static String getCacheDirectory(Context appContext) {
+ return appContext.getCacheDir().getPath();
+ }
+
+ /**
+ * @return the public downloads directory.
+ */
+ @SuppressWarnings("unused")
+ @CalledByNative
+ private static String getDownloadsDirectory(Context appContext) {
+ return Environment.getExternalStoragePublicDirectory(
+ Environment.DIRECTORY_DOWNLOADS).getPath();
+ }
+
+ /**
+ * @return the path to native libraries.
+ */
+ @SuppressWarnings("unused")
+ @CalledByNative
+ private static String getNativeLibraryDirectory(Context appContext) {
+ ApplicationInfo ai = appContext.getApplicationInfo();
+ if ((ai.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0 ||
+ (ai.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ return ai.nativeLibraryDir;
+ }
+
+ return "/system/lib/";
+ }
+
+ /**
+ * @return the external storage directory.
+ */
+ @SuppressWarnings("unused")
+ @CalledByNative
+ public static String getExternalStorageDirectory() {
+ return Environment.getExternalStorageDirectory().getAbsolutePath();
+ }
+}
diff --git a/src/base/android/java/src/org/chromium/base/PowerStatusReceiver.java b/src/base/android/java/src/org/chromium/base/PowerStatusReceiver.java
new file mode 100644
index 0000000..89594b8
--- /dev/null
+++ b/src/base/android/java/src/org/chromium/base/PowerStatusReceiver.java
@@ -0,0 +1,23 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+
+/**
+ * A BroadcastReceiver that listens to changes in power status and notifies
+ * SystemMonitor.
+ * It's instantiated by the framework via the application intent-filter
+ * declared in its manifest.
+ */
+public class PowerStatusReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ SystemMonitor.onBatteryChargingChanged(intent);
+ }
+}
diff --git a/src/base/android/java/src/org/chromium/base/SystemMessageHandler.java b/src/base/android/java/src/org/chromium/base/SystemMessageHandler.java
new file mode 100644
index 0000000..f7bb19f
--- /dev/null
+++ b/src/base/android/java/src/org/chromium/base/SystemMessageHandler.java
@@ -0,0 +1,93 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+class SystemMessageHandler extends Handler {
+
+ private static final int TIMER_MESSAGE = 1;
+ private static final int DELAYED_TIMER_MESSAGE = 2;
+
+ // Native class pointer set by the constructor of the SharedClient native class.
+ private int mMessagePumpDelegateNative = 0;
+
+ // Used to ensure we have at most one TIMER_MESSAGE pending at once.
+ private AtomicBoolean mTimerFired = new AtomicBoolean(true);
+
+ // Used to insert TIMER_MESSAGE on the front of the system message queue during startup only.
+ // This is a wee hack, to give a priority boost to native tasks during startup as they tend to
+ // be on the critical path. (After startup, handling the UI with minimum latency is more
+ // important).
+ private boolean mStartupComplete = false;
+ private final long mStartupCompleteTime = System.currentTimeMillis() + 2000;
+ private final boolean startupComplete() {
+ if (!mStartupComplete && System.currentTimeMillis() > mStartupCompleteTime) {
+ mStartupComplete = true;
+ }
+ return mStartupComplete;
+ }
+
+ private SystemMessageHandler(int messagePumpDelegateNative) {
+ mMessagePumpDelegateNative = messagePumpDelegateNative;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == TIMER_MESSAGE) {
+ mTimerFired.set(true);
+ }
+ while (nativeDoRunLoopOnce(mMessagePumpDelegateNative)) {
+ if (startupComplete()) {
+ setTimer();
+ break;
+ }
+ }
+ }
+
+ @CalledByNative
+ private void setTimer() {
+ if (!mTimerFired.getAndSet(false)) {
+ // mTimerFired was already false.
+ return;
+ }
+ if (startupComplete()) {
+ sendEmptyMessage(TIMER_MESSAGE);
+ } else {
+ sendMessageAtFrontOfQueue(obtainMessage(TIMER_MESSAGE));
+ }
+ }
+
+ // If millis <=0, it'll send a TIMER_MESSAGE instead of
+ // a DELAYED_TIMER_MESSAGE.
+ @SuppressWarnings("unused")
+ @CalledByNative
+ private void setDelayedTimer(long millis) {
+ if (millis <= 0) {
+ setTimer();
+ } else {
+ removeMessages(DELAYED_TIMER_MESSAGE);
+ sendEmptyMessageDelayed(DELAYED_TIMER_MESSAGE, millis);
+ }
+ }
+
+ @SuppressWarnings("unused")
+ @CalledByNative
+ private void removeTimer() {
+ removeMessages(TIMER_MESSAGE);
+ removeMessages(DELAYED_TIMER_MESSAGE);
+ }
+
+ @CalledByNative
+ private static SystemMessageHandler create(int messagePumpDelegateNative) {
+ return new SystemMessageHandler(messagePumpDelegateNative);
+ }
+
+ private native boolean nativeDoRunLoopOnce(int messagePumpDelegateNative);
+}
diff --git a/src/base/android/java/src/org/chromium/base/SystemMonitor.java b/src/base/android/java/src/org/chromium/base/SystemMonitor.java
new file mode 100644
index 0000000..30f61a6
--- /dev/null
+++ b/src/base/android/java/src/org/chromium/base/SystemMonitor.java
@@ -0,0 +1,90 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryManager;
+import android.os.Handler;
+import android.os.Looper;
+
+
+/**
+ * Integrates native SystemMonitor with the java side.
+ */
+@JNINamespace("base::android")
+public class SystemMonitor implements ActivityStatus.StateListener {
+ private static final long SUSPEND_DELAY_MS = 1 * 60 * 1000; // 1 minute.
+ private static SystemMonitor sInstance;
+
+ private boolean mIsBatteryPower;
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
+
+ // Asynchronous task used to fire the "paused" event to the native side 1 minute after the main
+ // activity transitioned to the "paused" state. This event is not sent immediately because it
+ // would be too aggressive. An Android activity can be in the "paused" state quite often. This
+ // can happen when a dialog window shows up for instance.
+ private static final Runnable sSuspendTask = new Runnable() {
+ @Override
+ public void run() {
+ nativeOnMainActivitySuspended();
+ }
+ };
+
+ public static void createForTests(Context context) {
+ // Applications will create this once the JNI side has been fully wired up both sides. For
+ // tests, we just need native -> java, that is, we don't need to notify java -> native on
+ // creation.
+ sInstance = new SystemMonitor();
+ }
+
+ public static void create(Context context) {
+ if (sInstance == null) {
+ sInstance = new SystemMonitor();
+ ActivityStatus.registerStateListener(sInstance);
+ IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+ Intent batteryStatusIntent = context.registerReceiver(null, ifilter);
+ onBatteryChargingChanged(batteryStatusIntent);
+ }
+ }
+
+ private SystemMonitor() {
+ }
+
+ public static void onBatteryChargingChanged(Intent intent) {
+ if (sInstance == null) {
+ // We may be called by the framework intent-filter before being fully initialized. This
+ // is not a problem, since our constructor will check for the state later on.
+ return;
+ }
+ int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
+ // If we're not plugged, assume we're running on battery power.
+ sInstance.mIsBatteryPower = chargePlug != BatteryManager.BATTERY_PLUGGED_USB &&
+ chargePlug != BatteryManager.BATTERY_PLUGGED_AC;
+ nativeOnBatteryChargingChanged();
+ }
+
+ @Override
+ public void onActivityStateChange(int newState) {
+ if (newState == ActivityStatus.RESUMED) {
+ // Remove the callback from the message loop in case it hasn't been executed yet.
+ mHandler.removeCallbacks(sSuspendTask);
+ nativeOnMainActivityResumed();
+ } else if (newState == ActivityStatus.PAUSED) {
+ mHandler.postDelayed(sSuspendTask, SUSPEND_DELAY_MS);
+ }
+ }
+
+ @CalledByNative
+ private static boolean isBatteryPower() {
+ return sInstance.mIsBatteryPower;
+ }
+
+ private static native void nativeOnBatteryChargingChanged();
+ private static native void nativeOnMainActivitySuspended();
+ private static native void nativeOnMainActivityResumed();
+}
diff --git a/src/base/android/java/src/org/chromium/base/ThreadUtils.java b/src/base/android/java/src/org/chromium/base/ThreadUtils.java
new file mode 100644
index 0000000..70232c4
--- /dev/null
+++ b/src/base/android/java/src/org/chromium/base/ThreadUtils.java
@@ -0,0 +1,152 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+
+/**
+ * Helper methods to deal with threading related tasks.
+ */
+public class ThreadUtils {
+
+ /**
+ * Run the supplied Runnable on the main thread. The method will block until
+ * the Runnable completes.
+ *
+ * @param r The Runnable to run.
+ */
+ public static void runOnUiThreadBlocking(final Runnable r) {
+ if (runningOnUiThread()) {
+ r.run();
+ } else {
+ FutureTask<Void> task = new FutureTask<Void>(r, null);
+ postOnUiThread(task);
+ try {
+ task.get();
+ } catch (Exception e) {
+ throw new RuntimeException("Exception occured while waiting for runnable", e);
+ }
+ }
+ }
+
+ /**
+ * Run the supplied Callable on the main thread, wrapping any exceptions in
+ * a RuntimeException. The method will block until the Callable completes.
+ *
+ * @param c The Callable to run
+ * @return The result of the callable
+ */
+ public static <T> T runOnUiThreadBlockingNoException(Callable<T> c) {
+ try {
+ return runOnUiThreadBlocking(c);
+ } catch (ExecutionException e) {
+ throw new RuntimeException("Error occured waiting for callable", e);
+ }
+ }
+
+ /**
+ * Run the supplied Callable on the main thread, The method will block until
+ * the Callable completes.
+ *
+ * @param c The Callable to run
+ * @return The result of the callable
+ * @throws ExecutionException c's exception
+ */
+ public static <T> T runOnUiThreadBlocking(Callable<T> c) throws ExecutionException {
+ FutureTask<T> task = new FutureTask<T>(c);
+ runOnUiThread(task);
+ try {
+ return task.get();
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted waiting for callable", e);
+ }
+ }
+
+ /**
+ * Run the supplied FutureTask on the main thread. The method will block
+ * only if the current thread is the main thread.
+ *
+ * @param task The FutureTask to run
+ * @return The queried task (to aid inline construction)
+ */
+ public static <T> FutureTask<T> runOnUiThread(FutureTask<T> task) {
+ if (runningOnUiThread()) {
+ task.run();
+ } else {
+ postOnUiThread(task);
+ }
+ return task;
+ }
+
+ /**
+ * Run the supplied Callable on the main thread. The method will block
+ * only if the current thread is the main thread.
+ *
+ * @param c The Callable to run
+ * @return A FutureTask wrapping the callable to retrieve results
+ */
+ public static <T> FutureTask<T> runOnUiThread(Callable<T> c) {
+ return runOnUiThread(new FutureTask<T>(c));
+ }
+
+ /**
+ * Run the supplied Runnable on the main thread. The method will block
+ * only if the current thread is the main thread.
+ *
+ * @param r The Runnable to run
+ */
+ public static void runOnUiThread(Runnable r) {
+ if (runningOnUiThread()) {
+ r.run();
+ } else {
+ LazyHolder.sUiThreadHandler.post(r);
+ }
+ }
+
+ /**
+ * Post the supplied FutureTask to run on the main thread. The method will
+ * not block, even if called on the UI thread.
+ *
+ * @param task The FutureTask to run
+ * @return The queried task (to aid inline construction)
+ */
+ public static <T> FutureTask<T> postOnUiThread(FutureTask<T> task) {
+ LazyHolder.sUiThreadHandler.post(task);
+ return task;
+ }
+
+ /**
+ * Post the supplied Runnable to run on the main thread. The method will
+ * not block, even if called on the UI thread.
+ *
+ * @param task The Runnable to run
+ */
+ public static void postOnUiThread(Runnable r) {
+ LazyHolder.sUiThreadHandler.post(r);
+ }
+
+ /**
+ * Asserts that the current thread is running on the main thread.
+ */
+ public static void assertOnUiThread() {
+ assert runningOnUiThread();
+ }
+
+ /**
+ * @return true iff the current thread is the main (UI) thread.
+ */
+ public static boolean runningOnUiThread() {
+ return Looper.getMainLooper() == Looper.myLooper();
+ }
+
+ private static class LazyHolder {
+ private static Handler sUiThreadHandler = new Handler(Looper.getMainLooper());
+ }
+}
diff --git a/src/base/android/java/src/org/chromium/base/WeakContext.java b/src/base/android/java/src/org/chromium/base/WeakContext.java
new file mode 100644
index 0000000..d660cc9
--- /dev/null
+++ b/src/base/android/java/src/org/chromium/base/WeakContext.java
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.content.Context;
+
+import java.lang.ref.WeakReference;
+import java.util.concurrent.Callable;
+
+// Holds a WeakReference to Context to allow it to be GC'd.
+// Also provides utility functions to getSystemService from the UI or any
+// other thread (may return null, if the Context has been nullified).
+public class WeakContext {
+ private static WeakReference<Context> sWeakContext;
+
+ public static void initializeWeakContext(final Context context) {
+ sWeakContext = new WeakReference<Context>(context);
+ }
+
+ public static Context getContext() {
+ return sWeakContext.get();
+ }
+
+ // Returns a system service. May be called from any thread.
+ // If necessary, it will send a message to the main thread to acquire the
+ // service, and block waiting for it to complete.
+ // May return null if context is no longer available.
+ public static Object getSystemService(final String name) {
+ final Context context = sWeakContext.get();
+ if (context == null) {
+ return null;
+ }
+ if (ThreadUtils.runningOnUiThread()) {
+ return context.getSystemService(name);
+ }
+ return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Object>() {
+ @Override
+ public Object call() {
+ return context.getSystemService(name);
+ }
+ });
+ }
+}
diff --git a/src/base/android/jni_android.cc b/src/base/android/jni_android.cc
new file mode 100644
index 0000000..fdc2170
--- /dev/null
+++ b/src/base/android/jni_android.cc
@@ -0,0 +1,327 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_android.h"
+
+#include <map>
+
+#include "base/android/build_info.h"
+#include "base/android/jni_string.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/threading/platform_thread.h"
+
+namespace {
+using base::android::GetClass;
+using base::android::MethodID;
+using base::android::ScopedJavaLocalRef;
+
+struct MethodIdentifier {
+ const char* class_name;
+ const char* method;
+ const char* jni_signature;
+
+ bool operator<(const MethodIdentifier& other) const {
+ int r = strcmp(class_name, other.class_name);
+ if (r < 0) {
+ return true;
+ } else if (r > 0) {
+ return false;
+ }
+
+ r = strcmp(method, other.method);
+ if (r < 0) {
+ return true;
+ } else if (r > 0) {
+ return false;
+ }
+
+ return strcmp(jni_signature, other.jni_signature) < 0;
+ }
+};
+
+typedef std::map<MethodIdentifier, jmethodID> MethodIDMap;
+
+const base::subtle::AtomicWord kUnlocked = 0;
+const base::subtle::AtomicWord kLocked = 1;
+base::subtle::AtomicWord g_method_id_map_lock = kUnlocked;
+JavaVM* g_jvm = NULL;
+// Leak the global app context, as it is used from a non-joinable worker thread
+// that may still be running at shutdown. There is no harm in doing this.
+base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >::Leaky
+ g_application_context = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<MethodIDMap> g_method_id_map = LAZY_INSTANCE_INITIALIZER;
+
+std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable) {
+ ScopedJavaLocalRef<jclass> throwable_clazz =
+ GetClass(env, "java/lang/Throwable");
+ jmethodID throwable_printstacktrace =
+ MethodID::Get<MethodID::TYPE_INSTANCE>(
+ env, throwable_clazz.obj(), "printStackTrace",
+ "(Ljava/io/PrintStream;)V");
+
+ // Create an instance of ByteArrayOutputStream.
+ ScopedJavaLocalRef<jclass> bytearray_output_stream_clazz =
+ GetClass(env, "java/io/ByteArrayOutputStream");
+ jmethodID bytearray_output_stream_constructor =
+ MethodID::Get<MethodID::TYPE_INSTANCE>(
+ env, bytearray_output_stream_clazz.obj(), "<init>", "()V");
+ jmethodID bytearray_output_stream_tostring =
+ MethodID::Get<MethodID::TYPE_INSTANCE>(
+ env, bytearray_output_stream_clazz.obj(), "toString",
+ "()Ljava/lang/String;");
+ ScopedJavaLocalRef<jobject> bytearray_output_stream(env,
+ env->NewObject(bytearray_output_stream_clazz.obj(),
+ bytearray_output_stream_constructor));
+
+ // Create an instance of PrintStream.
+ ScopedJavaLocalRef<jclass> printstream_clazz =
+ GetClass(env, "java/io/PrintStream");
+ jmethodID printstream_constructor =
+ MethodID::Get<MethodID::TYPE_INSTANCE>(
+ env, printstream_clazz.obj(), "<init>",
+ "(Ljava/io/OutputStream;)V");
+ ScopedJavaLocalRef<jobject> printstream(env,
+ env->NewObject(printstream_clazz.obj(), printstream_constructor,
+ bytearray_output_stream.obj()));
+
+ // Call Throwable.printStackTrace(PrintStream)
+ env->CallVoidMethod(java_throwable, throwable_printstacktrace,
+ printstream.obj());
+
+ // Call ByteArrayOutputStream.toString()
+ ScopedJavaLocalRef<jstring> exception_string(
+ env, static_cast<jstring>(
+ env->CallObjectMethod(bytearray_output_stream.obj(),
+ bytearray_output_stream_tostring)));
+
+ return ConvertJavaStringToUTF8(exception_string);
+}
+
+} // namespace
+
+namespace base {
+namespace android {
+
+JNIEnv* AttachCurrentThread() {
+ DCHECK(g_jvm);
+ JNIEnv* env = NULL;
+ jint ret = g_jvm->AttachCurrentThread(&env, NULL);
+ DCHECK_EQ(JNI_OK, ret);
+ return env;
+}
+
+void DetachFromVM() {
+ // Ignore the return value, if the thread is not attached, DetachCurrentThread
+ // will fail. But it is ok as the native thread may never be attached.
+ if (g_jvm)
+ g_jvm->DetachCurrentThread();
+}
+
+void InitVM(JavaVM* vm) {
+ DCHECK(!g_jvm);
+ g_jvm = vm;
+}
+
+void InitApplicationContext(const JavaRef<jobject>& context) {
+ DCHECK(g_application_context.Get().is_null());
+ g_application_context.Get().Reset(context);
+}
+
+const jobject GetApplicationContext() {
+ DCHECK(!g_application_context.Get().is_null());
+ return g_application_context.Get().obj();
+}
+
+ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env, const char* class_name) {
+ return ScopedJavaLocalRef<jclass>(env, GetUnscopedClass(env, class_name));
+}
+
+jclass GetUnscopedClass(JNIEnv* env, const char* class_name) {
+ jclass clazz = env->FindClass(class_name);
+ CHECK(!ClearException(env) && clazz) << "Failed to find class " << class_name;
+ return clazz;
+}
+
+bool HasClass(JNIEnv* env, const char* class_name) {
+ ScopedJavaLocalRef<jclass> clazz(env, env->FindClass(class_name));
+ if (!clazz.obj()) {
+ ClearException(env);
+ return false;
+ }
+ bool error = ClearException(env);
+ DCHECK(!error);
+ return true;
+}
+
+template<MethodID::Type type>
+jmethodID MethodID::Get(JNIEnv* env,
+ jclass clazz,
+ const char* method_name,
+ const char* jni_signature) {
+ jmethodID id = type == TYPE_STATIC ?
+ env->GetStaticMethodID(clazz, method_name, jni_signature) :
+ env->GetMethodID(clazz, method_name, jni_signature);
+ CHECK(base::android::ClearException(env) || id) <<
+ "Failed to find " <<
+ (type == TYPE_STATIC ? "static " : "") <<
+ "method " << method_name << " " << jni_signature;
+ return id;
+}
+
+// If |atomic_method_id| set, it'll return immediately. Otherwise, it'll call
+// into ::Get() above. If there's a race, it's ok since the values are the same
+// (and the duplicated effort will happen only once).
+template<MethodID::Type type>
+jmethodID MethodID::LazyGet(JNIEnv* env,
+ jclass clazz,
+ const char* method_name,
+ const char* jni_signature,
+ base::subtle::AtomicWord* atomic_method_id) {
+ COMPILE_ASSERT(sizeof(subtle::AtomicWord) >= sizeof(jmethodID),
+ AtomicWord_SmallerThan_jMethodID);
+ subtle::AtomicWord value = base::subtle::Acquire_Load(atomic_method_id);
+ if (value)
+ return reinterpret_cast<jmethodID>(value);
+ jmethodID id = MethodID::Get<type>(env, clazz, method_name, jni_signature);
+ base::subtle::Release_Store(
+ atomic_method_id, reinterpret_cast<subtle::AtomicWord>(id));
+ return id;
+}
+
+// Various template instantiations.
+template jmethodID MethodID::Get<MethodID::TYPE_STATIC>(
+ JNIEnv* env, jclass clazz, const char* method_name,
+ const char* jni_signature);
+
+template jmethodID MethodID::Get<MethodID::TYPE_INSTANCE>(
+ JNIEnv* env, jclass clazz, const char* method_name,
+ const char* jni_signature);
+
+template jmethodID MethodID::LazyGet<MethodID::TYPE_STATIC>(
+ JNIEnv* env, jclass clazz, const char* method_name,
+ const char* jni_signature, base::subtle::AtomicWord* atomic_method_id);
+
+template jmethodID MethodID::LazyGet<MethodID::TYPE_INSTANCE>(
+ JNIEnv* env, jclass clazz, const char* method_name,
+ const char* jni_signature, base::subtle::AtomicWord* atomic_method_id);
+
+jfieldID GetFieldID(JNIEnv* env,
+ const JavaRef<jclass>& clazz,
+ const char* field_name,
+ const char* jni_signature) {
+ jfieldID field_id = env->GetFieldID(clazz.obj(), field_name, jni_signature);
+ CHECK(!ClearException(env) && field_id) << "Failed to find field " <<
+ field_name << " " << jni_signature;
+ return field_id;
+}
+
+bool HasField(JNIEnv* env,
+ const JavaRef<jclass>& clazz,
+ const char* field_name,
+ const char* jni_signature) {
+ jfieldID field_id = env->GetFieldID(clazz.obj(), field_name, jni_signature);
+ if (!field_id) {
+ ClearException(env);
+ return false;
+ }
+ bool error = ClearException(env);
+ DCHECK(!error);
+ return true;
+}
+
+jfieldID GetStaticFieldID(JNIEnv* env,
+ const JavaRef<jclass>& clazz,
+ const char* field_name,
+ const char* jni_signature) {
+ jfieldID field_id =
+ env->GetStaticFieldID(clazz.obj(), field_name, jni_signature);
+ CHECK(!ClearException(env) && field_id) << "Failed to find static field " <<
+ field_name << " " << jni_signature;
+ return field_id;
+}
+
+jmethodID GetMethodIDFromClassName(JNIEnv* env,
+ const char* class_name,
+ const char* method,
+ const char* jni_signature) {
+ MethodIdentifier key;
+ key.class_name = class_name;
+ key.method = method;
+ key.jni_signature = jni_signature;
+
+ MethodIDMap* map = g_method_id_map.Pointer();
+ bool found = false;
+
+ while (base::subtle::Acquire_CompareAndSwap(&g_method_id_map_lock,
+ kUnlocked,
+ kLocked) != kUnlocked) {
+ base::PlatformThread::YieldCurrentThread();
+ }
+ MethodIDMap::const_iterator iter = map->find(key);
+ if (iter != map->end()) {
+ found = true;
+ }
+ base::subtle::Release_Store(&g_method_id_map_lock, kUnlocked);
+
+ // Addition to the map does not invalidate this iterator.
+ if (found) {
+ return iter->second;
+ }
+
+ ScopedJavaLocalRef<jclass> clazz(env, env->FindClass(class_name));
+ jmethodID id = MethodID::Get<MethodID::TYPE_INSTANCE>(
+ env, clazz.obj(), method, jni_signature);
+
+ while (base::subtle::Acquire_CompareAndSwap(&g_method_id_map_lock,
+ kUnlocked,
+ kLocked) != kUnlocked) {
+ base::PlatformThread::YieldCurrentThread();
+ }
+ // Another thread may have populated the map already.
+ std::pair<MethodIDMap::const_iterator, bool> result =
+ map->insert(std::make_pair(key, id));
+ DCHECK_EQ(id, result.first->second);
+ base::subtle::Release_Store(&g_method_id_map_lock, kUnlocked);
+
+ return id;
+}
+
+bool HasException(JNIEnv* env) {
+ return env->ExceptionCheck() != JNI_FALSE;
+}
+
+bool ClearException(JNIEnv* env) {
+ if (!HasException(env))
+ return false;
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ return true;
+}
+
+void CheckException(JNIEnv* env) {
+ if (!HasException(env)) return;
+
+ // Exception has been found, might as well tell breakpad about it.
+ jthrowable java_throwable = env->ExceptionOccurred();
+ if (!java_throwable) {
+ // Do nothing but return false.
+ CHECK(false);
+ }
+
+ // Clear the pending exception, since a local reference is now held.
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+
+ // Set the exception_string in BuildInfo so that breakpad can read it.
+ // RVO should avoid any extra copies of the exception string.
+ base::android::BuildInfo::GetInstance()->set_java_exception_info(
+ GetJavaExceptionInfo(env, java_throwable));
+
+ // Now, feel good about it and die.
+ CHECK(false);
+}
+
+} // namespace android
+} // namespace base
diff --git a/src/base/android/jni_android.h b/src/base/android/jni_android.h
new file mode 100644
index 0000000..16b85af
--- /dev/null
+++ b/src/base/android/jni_android.h
@@ -0,0 +1,137 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_JNI_ANDROID_H_
+#define BASE_ANDROID_JNI_ANDROID_H_
+
+#include <jni.h>
+#include <sys/types.h>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+namespace android {
+
+// Used to mark symbols to be exported in a shared library's symbol table.
+#define JNI_EXPORT __attribute__ ((visibility("default")))
+
+// Contains the registration method information for initializing JNI bindings.
+struct RegistrationMethod {
+ const char* name;
+ bool (*func)(JNIEnv* env);
+};
+
+// Attach the current thread to the VM (if necessary) and return the JNIEnv*.
+BASE_EXPORT JNIEnv* AttachCurrentThread();
+
+// Detach the current thread from VM if it is attached.
+BASE_EXPORT void DetachFromVM();
+
+// Initializes the global JVM. It is not necessarily called before
+// InitApplicationContext().
+BASE_EXPORT void InitVM(JavaVM* vm);
+
+// Initializes the global application context object. The |context| can be any
+// valid reference to the application context. Internally holds a global ref to
+// the context. InitVM and InitApplicationContext maybe called in either order.
+BASE_EXPORT void InitApplicationContext(const JavaRef<jobject>& context);
+
+// Gets a global ref to the application context set with
+// InitApplicationContext(). Ownership is retained by the function - the caller
+// must NOT release it.
+const BASE_EXPORT jobject GetApplicationContext();
+
+// Finds the class named |class_name| and returns it.
+// Use this method instead of invoking directly the JNI FindClass method (to
+// prevent leaking local references).
+// This method triggers a fatal assertion if the class could not be found.
+// Use HasClass if you need to check whether the class exists.
+BASE_EXPORT ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env,
+ const char* class_name);
+
+// Similar to the above, but the caller is responsible to manage the jclass
+// lifetime.
+BASE_EXPORT jclass GetUnscopedClass(JNIEnv* env,
+ const char* class_name) WARN_UNUSED_RESULT;
+
+// Returns true iff the class |class_name| could be found.
+BASE_EXPORT bool HasClass(JNIEnv* env, const char* class_name);
+
+// This class is a wrapper for JNIEnv Get(Static)MethodID.
+class BASE_EXPORT MethodID {
+ public:
+ enum Type {
+ TYPE_STATIC,
+ TYPE_INSTANCE,
+ };
+
+ // Returns the method ID for the method with the specified name and signature.
+ // This method triggers a fatal assertion if the method could not be found.
+ template<Type type>
+ static jmethodID Get(JNIEnv* env,
+ jclass clazz,
+ const char* method_name,
+ const char* jni_signature);
+
+ // The caller is responsible to zero-initialize |atomic_method_id|.
+ // It's fine to simultaneously call this on multiple threads referencing the
+ // same |atomic_method_id|.
+ template<Type type>
+ static jmethodID LazyGet(JNIEnv* env,
+ jclass clazz,
+ const char* method_name,
+ const char* jni_signature,
+ base::subtle::AtomicWord* atomic_method_id);
+};
+
+// Gets the method ID from the class name. Clears the pending Java exception
+// and returns NULL if the method is not found. Caches results. Note that
+// MethodID::Get() above avoids a class lookup, but does not cache results.
+// Strings passed to this function are held in the cache and MUST remain valid
+// beyond the duration of all future calls to this function, across all
+// threads. In practice, this means that the function should only be used with
+// string constants.
+BASE_EXPORT jmethodID GetMethodIDFromClassName(JNIEnv* env,
+ const char* class_name,
+ const char* method,
+ const char* jni_signature);
+
+// Gets the field ID for a class field.
+// This method triggers a fatal assertion if the field could not be found.
+BASE_EXPORT jfieldID GetFieldID(JNIEnv* env,
+ const JavaRef<jclass>& clazz,
+ const char* field_name,
+ const char* jni_signature);
+
+// Returns true if |clazz| as a field with the given name and signature.
+// TODO(jcivelli): Determine whether we explicitly have to pass the environment.
+BASE_EXPORT bool HasField(JNIEnv* env,
+ const JavaRef<jclass>& clazz,
+ const char* field_name,
+ const char* jni_signature);
+
+// Gets the field ID for a static class field.
+// This method triggers a fatal assertion if the field could not be found.
+BASE_EXPORT jfieldID GetStaticFieldID(JNIEnv* env,
+ const JavaRef<jclass>& clazz,
+ const char* field_name,
+ const char* jni_signature);
+
+// Returns true if an exception is pending in the provided JNIEnv*.
+BASE_EXPORT bool HasException(JNIEnv* env);
+
+// If an exception is pending in the provided JNIEnv*, this function clears it
+// and returns true.
+BASE_EXPORT bool ClearException(JNIEnv* env);
+
+// This function will call CHECK() macro if there's any pending exception.
+BASE_EXPORT void CheckException(JNIEnv* env);
+
+} // namespace android
+} // namespace base
+
+#endif // BASE_ANDROID_JNI_ANDROID_H_
diff --git a/src/base/android/jni_android_unittest.cc b/src/base/android/jni_android_unittest.cc
new file mode 100644
index 0000000..920b395
--- /dev/null
+++ b/src/base/android/jni_android_unittest.cc
@@ -0,0 +1,141 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_android.h"
+
+#include "base/at_exit.h"
+#include "base/logging.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+namespace {
+
+const char kJavaLangObject[] = "java/lang/Object";
+const char kGetClass[] = "getClass";
+const char kToString[] = "toString";
+const char kReturningJavaLangClass[] = "()Ljava/lang/Class;";
+const char kReturningJavaLangString[] = "()Ljava/lang/String;";
+
+const char* g_last_method;
+const char* g_last_jni_signature;
+jmethodID g_last_method_id;
+
+const JNINativeInterface* g_previous_functions;
+
+jmethodID GetMethodIDWrapper(JNIEnv* env, jclass clazz, const char* method,
+ const char* jni_signature) {
+ g_last_method = method;
+ g_last_jni_signature = jni_signature;
+ g_last_method_id = g_previous_functions->GetMethodID(env, clazz, method,
+ jni_signature);
+ return g_last_method_id;
+}
+
+} // namespace
+
+class JNIAndroidTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ JNIEnv* env = AttachCurrentThread();
+ g_previous_functions = env->functions;
+ hooked_functions = *g_previous_functions;
+ env->functions = &hooked_functions;
+ hooked_functions.GetMethodID = &GetMethodIDWrapper;
+ }
+
+ virtual void TearDown() {
+ JNIEnv* env = AttachCurrentThread();
+ env->functions = g_previous_functions;
+ Reset();
+ }
+
+ void Reset() {
+ g_last_method = 0;
+ g_last_jni_signature = 0;
+ g_last_method_id = NULL;
+ }
+ // Needed to cleanup the cached method map in the implementation between
+ // runs (e.g. if using --gtest_repeat)
+ base::ShadowingAtExitManager exit_manager;
+ // From JellyBean release, the instance of this struct provided in JNIEnv is
+ // read-only, so we deep copy it to allow individual functions to be hooked.
+ JNINativeInterface hooked_functions;
+};
+
+TEST_F(JNIAndroidTest, GetMethodIDFromClassNameCaching) {
+ JNIEnv* env = AttachCurrentThread();
+
+ Reset();
+ jmethodID id1 = GetMethodIDFromClassName(env, kJavaLangObject, kGetClass,
+ kReturningJavaLangClass);
+ EXPECT_STREQ(kGetClass, g_last_method);
+ EXPECT_STREQ(kReturningJavaLangClass, g_last_jni_signature);
+ EXPECT_EQ(g_last_method_id, id1);
+
+ Reset();
+ jmethodID id2 = GetMethodIDFromClassName(env, kJavaLangObject, kGetClass,
+ kReturningJavaLangClass);
+ EXPECT_STREQ(0, g_last_method);
+ EXPECT_STREQ(0, g_last_jni_signature);
+ EXPECT_EQ(NULL, g_last_method_id);
+ EXPECT_EQ(id1, id2);
+
+ Reset();
+ jmethodID id3 = GetMethodIDFromClassName(env, kJavaLangObject, kToString,
+ kReturningJavaLangString);
+ EXPECT_STREQ(kToString, g_last_method);
+ EXPECT_STREQ(kReturningJavaLangString, g_last_jni_signature);
+ EXPECT_EQ(g_last_method_id, id3);
+}
+
+namespace {
+
+base::subtle::AtomicWord g_atomic_id = 0;
+int LazyMethodIDCall(JNIEnv* env, jclass clazz, int p) {
+ jmethodID id = base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_STATIC>(
+ env, clazz,
+ "abs",
+ "(I)I",
+ &g_atomic_id);
+
+ return env->CallStaticIntMethod(clazz, id, p);
+}
+
+int MethodIDCall(JNIEnv* env, jclass clazz, jmethodID id, int p) {
+ return env->CallStaticIntMethod(clazz, id, p);
+}
+
+} // namespace
+
+TEST(JNIAndroidMicrobenchmark, MethodId) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jclass> clazz(GetClass(env, "java/lang/Math"));
+ base::Time start_lazy = base::Time::Now();
+ int o = 0;
+ for (int i = 0; i < 1024; ++i)
+ o += LazyMethodIDCall(env, clazz.obj(), i);
+ base::Time end_lazy = base::Time::Now();
+
+ jmethodID id = reinterpret_cast<jmethodID>(g_atomic_id);
+ base::Time start = base::Time::Now();
+ for (int i = 0; i < 1024; ++i)
+ o += MethodIDCall(env, clazz.obj(), id, i);
+ base::Time end = base::Time::Now();
+
+ // On a Galaxy Nexus, results were in the range of:
+ // JNI LazyMethodIDCall (us) 1984
+ // JNI MethodIDCall (us) 1861
+ LOG(ERROR) << "JNI LazyMethodIDCall (us) " <<
+ base::TimeDelta(end_lazy - start_lazy).InMicroseconds();
+ LOG(ERROR) << "JNI MethodIDCall (us) " <<
+ base::TimeDelta(end - start).InMicroseconds();
+ LOG(ERROR) << "JNI " << o;
+}
+
+
+} // namespace android
+} // namespace base
diff --git a/src/base/android/jni_array.cc b/src/base/android/jni_array.cc
new file mode 100644
index 0000000..fe2aadb
--- /dev/null
+++ b/src/base/android/jni_array.cc
@@ -0,0 +1,153 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_array.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/logging.h"
+
+namespace base {
+namespace android {
+
+ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(
+ JNIEnv* env, const uint8* bytes, size_t len) {
+ jbyteArray byte_array = env->NewByteArray(len);
+ CheckException(env);
+ DCHECK(byte_array);
+
+ jbyte* elements = env->GetByteArrayElements(byte_array, NULL);
+ memcpy(elements, bytes, len);
+ env->ReleaseByteArrayElements(byte_array, elements, 0);
+ CheckException(env);
+
+ return ScopedJavaLocalRef<jbyteArray>(env, byte_array);
+}
+
+ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfByteArray(
+ JNIEnv* env, const std::vector<std::string>& v) {
+ ScopedJavaLocalRef<jclass> byte_array_clazz = GetClass(env, "[B");
+ jobjectArray joa = env->NewObjectArray(v.size(),
+ byte_array_clazz.obj(), NULL);
+ CheckException(env);
+
+ for (size_t i = 0; i < v.size(); ++i) {
+ ScopedJavaLocalRef<jbyteArray> byte_array = ToJavaByteArray(env,
+ reinterpret_cast<const uint8*>(v[i].data()), v[i].length());
+ env->SetObjectArrayElement(joa, i, byte_array.obj());
+ }
+ return ScopedJavaLocalRef<jobjectArray>(env, joa);
+}
+
+ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
+ JNIEnv* env, const std::vector<std::string>& v) {
+ ScopedJavaLocalRef<jclass> string_clazz = GetClass(env, "java/lang/String");
+ jobjectArray joa = env->NewObjectArray(v.size(), string_clazz.obj(), NULL);
+ CheckException(env);
+
+ for (size_t i = 0; i < v.size(); ++i) {
+ ScopedJavaLocalRef<jstring> item = ConvertUTF8ToJavaString(env, v[i]);
+ env->SetObjectArrayElement(joa, i, item.obj());
+ }
+ return ScopedJavaLocalRef<jobjectArray>(env, joa);
+}
+
+ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
+ JNIEnv* env, const std::vector<string16>& v) {
+ ScopedJavaLocalRef<jclass> string_clazz = GetClass(env, "java/lang/String");
+ jobjectArray joa = env->NewObjectArray(v.size(), string_clazz.obj(), NULL);
+ CheckException(env);
+
+ for (size_t i = 0; i < v.size(); ++i) {
+ ScopedJavaLocalRef<jstring> item = ConvertUTF16ToJavaString(env, v[i]);
+ env->SetObjectArrayElement(joa, i, item.obj());
+ }
+ return ScopedJavaLocalRef<jobjectArray>(env, joa);
+}
+
+void AppendJavaStringArrayToStringVector(JNIEnv* env,
+ jobjectArray array,
+ std::vector<string16>* out) {
+ DCHECK(out);
+ if (!array)
+ return;
+ jsize len = env->GetArrayLength(array);
+ size_t back = out->size();
+ out->resize(back + len);
+ for (jsize i = 0; i < len; ++i) {
+ ScopedJavaLocalRef<jstring> str(env,
+ static_cast<jstring>(env->GetObjectArrayElement(array, i)));
+ ConvertJavaStringToUTF16(env, str.obj(), &((*out)[back + i]));
+ }
+}
+
+void AppendJavaStringArrayToStringVector(JNIEnv* env,
+ jobjectArray array,
+ std::vector<std::string>* out) {
+ DCHECK(out);
+ if (!array)
+ return;
+ jsize len = env->GetArrayLength(array);
+ size_t back = out->size();
+ out->resize(back + len);
+ for (jsize i = 0; i < len; ++i) {
+ ScopedJavaLocalRef<jstring> str(env,
+ static_cast<jstring>(env->GetObjectArrayElement(array, i)));
+ ConvertJavaStringToUTF8(env, str.obj(), &((*out)[back + i]));
+ }
+}
+
+void AppendJavaByteArrayToByteVector(JNIEnv* env,
+ jbyteArray byte_array,
+ std::vector<uint8>* out) {
+ DCHECK(out);
+ if (!byte_array)
+ return;
+ jsize len = env->GetArrayLength(byte_array);
+ jbyte* bytes = env->GetByteArrayElements(byte_array, NULL);
+ out->insert(out->end(), bytes, bytes + len);
+ env->ReleaseByteArrayElements(byte_array, bytes, JNI_ABORT);
+}
+
+void JavaByteArrayToByteVector(JNIEnv* env,
+ jbyteArray byte_array,
+ std::vector<uint8>* out) {
+ DCHECK(out);
+ out->clear();
+ AppendJavaByteArrayToByteVector(env, byte_array, out);
+}
+
+void JavaIntArrayToIntVector(JNIEnv* env,
+ jintArray array,
+ std::vector<int>* out) {
+ DCHECK(out);
+ out->clear();
+ jsize len = env->GetArrayLength(array);
+ jint* ints = env->GetIntArrayElements(array, NULL);
+ for (jsize i = 0; i < len; ++i) {
+ out->push_back(static_cast<int>(ints[i]));
+ }
+ env->ReleaseIntArrayElements(array, ints, JNI_ABORT);
+}
+
+void JavaArrayOfByteArrayToStringVector(
+ JNIEnv* env,
+ jobjectArray array,
+ std::vector<std::string>* out) {
+ DCHECK(out);
+ out->clear();
+ jsize len = env->GetArrayLength(array);
+ out->resize(len);
+ for (jsize i = 0; i < len; ++i) {
+ jbyteArray bytes_array = static_cast<jbyteArray>(
+ env->GetObjectArrayElement(array, i));
+ jsize bytes_len = env->GetArrayLength(bytes_array);
+ jbyte* bytes = env->GetByteArrayElements(bytes_array, NULL);
+ (*out)[i].assign(reinterpret_cast<const char*>(bytes), bytes_len);
+ env->ReleaseByteArrayElements(bytes_array, bytes, JNI_ABORT);
+ }
+}
+
+} // namespace android
+} // namespace base
diff --git a/src/base/android/jni_array.h b/src/base/android/jni_array.h
new file mode 100644
index 0000000..fbc131e
--- /dev/null
+++ b/src/base/android/jni_array.h
@@ -0,0 +1,73 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_JNI_ARRAY_H_
+#define BASE_ANDROID_JNI_ARRAY_H_
+
+#include <jni.h>
+#include <string>
+#include <vector>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/string16.h"
+
+namespace base {
+namespace android {
+
+// Returns a new Java byte array converted from the given bytes array.
+BASE_EXPORT ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(
+ JNIEnv* env, const uint8* bytes, size_t len);
+
+// Returns a array of Java byte array converted from |v|.
+BASE_EXPORT ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfByteArray(
+ JNIEnv* env, const std::vector<std::string>& v);
+
+BASE_EXPORT ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
+ JNIEnv* env, const std::vector<std::string>& v);
+
+BASE_EXPORT ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
+ JNIEnv* env, const std::vector<string16>& v);
+
+// Converts a Java string array to a native array.
+BASE_EXPORT void AppendJavaStringArrayToStringVector(
+ JNIEnv* env,
+ jobjectArray array,
+ std::vector<string16>* out);
+
+BASE_EXPORT void AppendJavaStringArrayToStringVector(
+ JNIEnv* env,
+ jobjectArray array,
+ std::vector<std::string>* out);
+
+// Appends the Java bytes in |bytes_array| onto the end of |out|.
+BASE_EXPORT void AppendJavaByteArrayToByteVector(
+ JNIEnv* env,
+ jbyteArray byte_array,
+ std::vector<uint8>* out);
+
+// Replaces the content of |out| with the Java bytes in |bytes_array|.
+BASE_EXPORT void JavaByteArrayToByteVector(
+ JNIEnv* env,
+ jbyteArray byte_array,
+ std::vector<uint8>* out);
+
+// Replaces the content of |out| with the Java ints in |int_array|.
+BASE_EXPORT void JavaIntArrayToIntVector(
+ JNIEnv* env,
+ jintArray int_array,
+ std::vector<int>* out);
+
+// Assuming |array| is an byte[][] (array of byte arrays), replaces the
+// content of |out| with the corresponding vector of strings. No UTF-8
+// conversion is performed.
+void JavaArrayOfByteArrayToStringVector(
+ JNIEnv* env,
+ jobjectArray array,
+ std::vector<std::string>* out);
+
+} // namespace android
+} // namespace base
+
+#endif // BASE_ANDROID_JNI_ARRAY_H_
diff --git a/src/base/android/jni_array_unittest.cc b/src/base/android/jni_array_unittest.cc
new file mode 100644
index 0000000..a4e3025
--- /dev/null
+++ b/src/base/android/jni_array_unittest.cc
@@ -0,0 +1,67 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_array.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+TEST(JniArray, BasicConversions) {
+ const uint8 kBytes[] = { 0, 1, 2, 3 };
+ const size_t kLen = arraysize(kBytes);
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jbyteArray> bytes = ToJavaByteArray(env, kBytes, kLen);
+ ASSERT_TRUE(bytes.obj());
+
+ std::vector<uint8> vec(5);
+ JavaByteArrayToByteVector(env, bytes.obj(), &vec);
+ EXPECT_EQ(4U, vec.size());
+ EXPECT_EQ(std::vector<uint8>(kBytes, kBytes + kLen), vec);
+
+ AppendJavaByteArrayToByteVector(env, bytes.obj(), &vec);
+ EXPECT_EQ(8U, vec.size());
+}
+
+TEST(JniArray, JavaArrayOfByteArrayToStringVector) {
+ const int kMaxItems = 50;
+ JNIEnv* env = AttachCurrentThread();
+
+ // Create a byte[][] object.
+ ScopedJavaLocalRef<jclass> byte_array_clazz(env, env->FindClass("[B"));
+ ASSERT_TRUE(byte_array_clazz.obj());
+
+ ScopedJavaLocalRef<jobjectArray> array(
+ env, env->NewObjectArray(kMaxItems, byte_array_clazz.obj(), NULL));
+ ASSERT_TRUE(array.obj());
+
+ // Create kMaxItems byte buffers.
+ char text[16];
+ for (int i = 0; i < kMaxItems; ++i) {
+ snprintf(text, sizeof text, "%d", i);
+ ScopedJavaLocalRef<jbyteArray> byte_array = ToJavaByteArray(
+ env, reinterpret_cast<uint8*>(text),
+ static_cast<size_t>(strlen(text)));
+ ASSERT_TRUE(byte_array.obj());
+
+ env->SetObjectArrayElement(array.obj(), i, byte_array.obj());
+ ASSERT_FALSE(HasException(env));
+ }
+
+ // Convert to std::vector<std::string>, check the content.
+ std::vector<std::string> vec;
+ JavaArrayOfByteArrayToStringVector(env, array.obj(), &vec);
+
+ EXPECT_EQ(static_cast<size_t>(kMaxItems), vec.size());
+ for (int i = 0; i < kMaxItems; ++i) {
+ snprintf(text, sizeof text, "%d", i);
+ EXPECT_STREQ(text, vec[i].c_str());
+ }
+}
+
+} // namespace android
+} // namespace base
diff --git a/src/base/android/jni_generator/SampleForTests.java b/src/base/android/jni_generator/SampleForTests.java
new file mode 100644
index 0000000..341f0ea
--- /dev/null
+++ b/src/base/android/jni_generator/SampleForTests.java
@@ -0,0 +1,171 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.example.jni_generator;
+
+import android.graphics.Rect;
+
+// This class serves as a reference test for the bindings generator, and as example documentation
+// for how to use the jni generator.
+// The C++ counter-part is sample_for_tests.cc.
+// jni_generator.gyp has a jni_generator_tests target that will:
+// * Generate a header file for the JNI bindings based on this file.
+// * Compile sample_for_tests.cc using the generated header file.
+// * link a native executable to prove the generated header + cc file are self-contained.
+// All comments are informational only, and are ignored by the jni generator.
+//
+// This JNINamespace annotation indicates that all native methods should be
+// generated inside this namespace, including the native class that this
+// object binds to.
+@JNINamespace("base::android")
+class SampleForTests {
+ // Classes can store their C++ pointer counter part as an int that is normally initialized by
+ // calling out a nativeInit() function.
+ int nativePtr;
+
+ // You can define methods and attributes on the java class just like any other.
+ // Methods without the @CalledByNative annotation won't be exposed to JNI.
+ public SampleForTests() {
+ }
+
+ public void startExample() {
+ // Calls native code and holds a pointer to the C++ class.
+ nativePtr = nativeInit("myParam");
+ }
+
+ public void doStuff() {
+ // This will call CPPClass::Method() using nativePtr as a pointer to the object. This must be
+ // done to:
+ // * avoid leaks.
+ // * using finalizers are not allowed to destroy the cpp class.
+ nativeMethod(nativePtr);
+ }
+
+ public void finishExample() {
+ // We're done, so let's destroy nativePtr object.
+ nativeDestroy(nativePtr);
+ }
+
+ // -----------------------------------------------------------------------------------------------
+ // The following methods demonstrate exporting Java methods for invocation from C++ code.
+ // Java functions are mapping into C global functions by prefixing the method name with
+ // "Java_<Class>_"
+ // This is triggered by the @CalledByNative annotation; the methods may be named as you wish.
+
+ // Exported to C++ as:
+ // Java_Example_javaMethod(JNIEnv* env, jobject obj, jint foo, jint bar)
+ // Typically the C++ code would have obtained the jobject via the Init() call described above.
+ @CalledByNative
+ public int javaMethod(int foo,
+ int bar) {
+ return 0;
+ }
+
+ // Exported to C++ as Java_Example_staticJavaMethod(JNIEnv* env)
+ // Note no jobject argument, as it is static.
+ @CalledByNative
+ public static boolean staticJavaMethod() {
+ return true;
+ }
+
+ // No prefix, so this method is package private. It will still be exported.
+ @CalledByNative
+ void packagePrivateJavaMethod() {}
+
+ // Note the "Unchecked" suffix. By default, @CalledByNative will always generate bindings that
+ // call CheckException(). With "@CalledByNativeUnchecked", the client C++ code is responsible to
+ // call ClearException() and act as appropriate.
+ // See more details at the "@CalledByNativeUnchecked" annotation.
+ @CalledByNativeUnchecked
+ void methodThatThrowsException() throws Exception {}
+
+ // The generator is not confused by inline comments:
+ // @CalledByNative void thisShouldNotAppearInTheOutput();
+ // @CalledByNativeUnchecked public static void neitherShouldThis(int foo);
+
+ /**
+ * The generator is not confused by block comments:
+ * @CalledByNative void thisShouldNotAppearInTheOutputEither();
+ * @CalledByNativeUnchecked public static void andDefinitelyNotThis(int foo);
+ */
+
+ // String constants that look like comments don't confuse the generator:
+ private String arrgh = "*/*";
+
+ //------------------------------------------------------------------------------------------------
+ // Java fields which are accessed from C++ code only must be annotated with @AccessedByNative to
+ // prevent them being eliminated when unreferenced code is stripped.
+ @AccessedByNative
+ private int javaField;
+
+ //------------------------------------------------------------------------------------------------
+ // The following methods demonstrate declaring methods to call into C++ from Java.
+ // The generator detects the "native" and "static" keywords, the type and name of the first
+ // parameter, and the "native" prefix to the function name to determine the C++ function
+ // signatures. Besides these constraints the methods can be freely named.
+
+ // This declares a C++ function which the application code must implement:
+ // static jint Init(JNIEnv* env, jobject obj);
+ // The jobject parameter refers back to this java side object instance.
+ // The implementation must return the pointer to the C++ object cast to jint.
+ // The caller of this method should store it, and supply it as a the nativeCPPClass param to
+ // subsequent native method calls (see the methods below that take an "int native..." as first
+ // param).
+ private native int nativeInit();
+
+ // This defines a function binding to the associated C++ class member function. The name is
+ // derived from |nativeDestroy| and |nativeCPPClass| to arrive at CPPClass::Destroy() (i.e. native
+ // prefixes stripped).
+ // The |nativeCPPClass| is automatically cast to type CPPClass* in order to obtain the object on
+ // which to invoke the member function.
+ private native void nativeDestroy(int nativeCPPClass);
+
+ // This declares a C++ function which the application code must implement:
+ // static jdouble GetDoubleFunction(JNIEnv* env, jobject obj);
+ // The jobject parameter refers back to this java side object instance.
+ private native double nativeGetDoubleFunction();
+
+ // Similar to nativeGetDoubleFunction(), but here the C++ side will receive a jclass rather than
+ // jobject param, as the function is declared static.
+ private static native float nativeGetFloatFunction();
+
+ // This function takes a non-POD datatype. We have a list mapping them to their full classpath in
+ // jni_generator.py JavaParamToJni. If you require a new datatype, make sure you add to that
+ // function.
+ private native void nativeSetNonPODDatatype(Rect rect);
+
+ // This declares a C++ function which the application code must implement:
+ // static ScopedJavaLocalRef<jobject> GetNonPODDatatype(JNIEnv* env, jobject obj);
+ // The jobject parameter refers back to this java side object instance.
+ // Note that it returns a ScopedJavaLocalRef<jobject> so that you don' have to worry about
+ // deleting the JNI local reference. This is similar with Strings and arrays.
+ private native Object nativeGetNonPODDatatype();
+
+ // Similar to nativeDestroy above, this will cast nativeCPPClass into pointer of CPPClass type and
+ // call its Method member function.
+ private native int nativeMethod(int nativeCPPClass);
+
+ // Similar to nativeMethod above, but here the C++ fully qualified class name is taken from the
+ // annotation rather than parameter name, which can thus be chosen freely.
+ @NativeClassQualifiedName("CPPClass::InnerClass")
+ private native double nativeMethodOtherP0(int nativePtr);
+
+ // An inner class has some special attributes for annotation.
+ class InnerClass {
+ @CalledByNative("InnerClass")
+ public float JavaInnerMethod() {
+ }
+
+ @CalledByNative("InnerClass")
+ public static void javaInnerFunction() {
+ }
+
+ @NativeCall("InnerClass")
+ private static native int nativeInnerFunction();
+
+ @NativeCall("InnerClass")
+ private static native String nativeInnerMethod(int nativeCPPClass);
+
+ }
+}
diff --git a/src/base/android/jni_generator/golden_sample_for_tests_jni.h b/src/base/android/jni_generator/golden_sample_for_tests_jni.h
new file mode 100644
index 0000000..08f25a7
--- /dev/null
+++ b/src/base/android/jni_generator/golden_sample_for_tests_jni.h
@@ -0,0 +1,293 @@
+// Copyright (c) 2012 The Chromium Authors. 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 autogenerated by
+// base/android/jni_generator/jni_generator_tests.py
+// For
+// org/chromium/example/jni_generator/SampleForTests
+
+#ifndef org_chromium_example_jni_generator_SampleForTests_JNI
+#define org_chromium_example_jni_generator_SampleForTests_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+using base::android::ScopedJavaLocalRef;
+
+// Step 1: forward declarations.
+namespace {
+const char kInnerClassClassPath[] =
+ "org/chromium/example/jni_generator/SampleForTests$InnerClass";
+const char kSampleForTestsClassPath[] =
+ "org/chromium/example/jni_generator/SampleForTests";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_InnerClass_clazz = NULL;
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_SampleForTests_clazz = NULL;
+} // namespace
+
+namespace base {
+namespace android {
+
+static jint Init(JNIEnv* env, jobject obj);
+
+static jdouble GetDoubleFunction(JNIEnv* env, jobject obj);
+
+static jfloat GetFloatFunction(JNIEnv* env, jclass clazz);
+
+static void SetNonPODDatatype(JNIEnv* env, jobject obj,
+ jobject rect);
+
+static jobject GetNonPODDatatype(JNIEnv* env, jobject obj);
+
+static jint InnerFunction(JNIEnv* env, jclass clazz);
+
+// Step 2: method stubs.
+static void Destroy(JNIEnv* env, jobject obj,
+ jint nativeCPPClass) {
+ DCHECK(nativeCPPClass) << "Destroy";
+ CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
+ return native->Destroy(env, obj);
+}
+
+static jint Method(JNIEnv* env, jobject obj,
+ jint nativeCPPClass) {
+ DCHECK(nativeCPPClass) << "Method";
+ CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
+ return native->Method(env, obj);
+}
+
+static jdouble MethodOtherP0(JNIEnv* env, jobject obj,
+ jint nativePtr) {
+ DCHECK(nativePtr) << "MethodOtherP0";
+ CPPClass::InnerClass* native =
+ reinterpret_cast<CPPClass::InnerClass*>(nativePtr);
+ return native->MethodOtherP0(env, obj);
+}
+
+static jstring InnerMethod(JNIEnv* env, jobject obj,
+ jint nativeCPPClass) {
+ DCHECK(nativeCPPClass) << "InnerMethod";
+ CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
+ return native->InnerMethod(env, obj).Release();
+}
+
+static base::subtle::AtomicWord g_SampleForTests_javaMethod = 0;
+static jint Java_SampleForTests_javaMethod(JNIEnv* env, jobject obj, jint foo,
+ jint bar) {
+ /* Must call RegisterNativesImpl() */
+ DCHECK(g_SampleForTests_clazz);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_INSTANCE>(
+ env, g_SampleForTests_clazz,
+ "javaMethod",
+
+"("
+"I"
+"I"
+")"
+"I",
+ &g_SampleForTests_javaMethod);
+
+ jint ret =
+ env->CallIntMethod(obj,
+ method_id, foo, bar);
+ base::android::CheckException(env);
+ return ret;
+}
+
+static base::subtle::AtomicWord g_SampleForTests_staticJavaMethod = 0;
+static jboolean Java_SampleForTests_staticJavaMethod(JNIEnv* env) {
+ /* Must call RegisterNativesImpl() */
+ DCHECK(g_SampleForTests_clazz);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_STATIC>(
+ env, g_SampleForTests_clazz,
+ "staticJavaMethod",
+
+"("
+")"
+"Z",
+ &g_SampleForTests_staticJavaMethod);
+
+ jboolean ret =
+ env->CallStaticBooleanMethod(g_SampleForTests_clazz,
+ method_id);
+ base::android::CheckException(env);
+ return ret;
+}
+
+static base::subtle::AtomicWord g_SampleForTests_packagePrivateJavaMethod = 0;
+static void Java_SampleForTests_packagePrivateJavaMethod(JNIEnv* env, jobject
+ obj) {
+ /* Must call RegisterNativesImpl() */
+ DCHECK(g_SampleForTests_clazz);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_INSTANCE>(
+ env, g_SampleForTests_clazz,
+ "packagePrivateJavaMethod",
+
+"("
+")"
+"V",
+ &g_SampleForTests_packagePrivateJavaMethod);
+
+ env->CallVoidMethod(obj,
+ method_id);
+ base::android::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_SampleForTests_methodThatThrowsException = 0;
+static void Java_SampleForTests_methodThatThrowsException(JNIEnv* env, jobject
+ obj) {
+ /* Must call RegisterNativesImpl() */
+ DCHECK(g_SampleForTests_clazz);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_INSTANCE>(
+ env, g_SampleForTests_clazz,
+ "methodThatThrowsException",
+
+"("
+")"
+"V",
+ &g_SampleForTests_methodThatThrowsException);
+
+ env->CallVoidMethod(obj,
+ method_id);
+
+}
+
+static base::subtle::AtomicWord g_InnerClass_JavaInnerMethod = 0;
+static jfloat Java_InnerClass_JavaInnerMethod(JNIEnv* env, jobject obj) {
+ /* Must call RegisterNativesImpl() */
+ DCHECK(g_InnerClass_clazz);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_INSTANCE>(
+ env, g_InnerClass_clazz,
+ "JavaInnerMethod",
+
+"("
+")"
+"F",
+ &g_InnerClass_JavaInnerMethod);
+
+ jfloat ret =
+ env->CallFloatMethod(obj,
+ method_id);
+ base::android::CheckException(env);
+ return ret;
+}
+
+static base::subtle::AtomicWord g_InnerClass_javaInnerFunction = 0;
+static void Java_InnerClass_javaInnerFunction(JNIEnv* env) {
+ /* Must call RegisterNativesImpl() */
+ DCHECK(g_InnerClass_clazz);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_STATIC>(
+ env, g_InnerClass_clazz,
+ "javaInnerFunction",
+
+"("
+")"
+"V",
+ &g_InnerClass_javaInnerFunction);
+
+ env->CallStaticVoidMethod(g_InnerClass_clazz,
+ method_id);
+ base::android::CheckException(env);
+
+}
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+ g_InnerClass_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+ base::android::GetUnscopedClass(env, kInnerClassClassPath)));
+ g_SampleForTests_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+ base::android::GetUnscopedClass(env, kSampleForTestsClassPath)));
+ static const JNINativeMethod kMethodsInnerClass[] = {
+ { "nativeInnerFunction",
+"("
+")"
+"I", reinterpret_cast<void*>(InnerFunction) },
+ { "nativeInnerMethod",
+"("
+"I"
+")"
+"Ljava/lang/String;", reinterpret_cast<void*>(InnerMethod) },
+ };
+ const int kMethodsInnerClassSize = arraysize(kMethodsInnerClass);
+
+ if (env->RegisterNatives(g_InnerClass_clazz,
+ kMethodsInnerClass,
+ kMethodsInnerClassSize) < 0) {
+ LOG(ERROR) << "RegisterNatives failed in " << __FILE__;
+ return false;
+ }
+
+ static const JNINativeMethod kMethodsSampleForTests[] = {
+ { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+ { "nativeDestroy",
+"("
+"I"
+")"
+"V", reinterpret_cast<void*>(Destroy) },
+ { "nativeGetDoubleFunction",
+"("
+")"
+"D", reinterpret_cast<void*>(GetDoubleFunction) },
+ { "nativeGetFloatFunction",
+"("
+")"
+"F", reinterpret_cast<void*>(GetFloatFunction) },
+ { "nativeSetNonPODDatatype",
+"("
+"Landroid/graphics/Rect;"
+")"
+"V", reinterpret_cast<void*>(SetNonPODDatatype) },
+ { "nativeGetNonPODDatatype",
+"("
+")"
+"Ljava/lang/Object;", reinterpret_cast<void*>(GetNonPODDatatype) },
+ { "nativeMethod",
+"("
+"I"
+")"
+"I", reinterpret_cast<void*>(Method) },
+ { "nativeMethodOtherP0",
+"("
+"I"
+")"
+"D", reinterpret_cast<void*>(MethodOtherP0) },
+ };
+ const int kMethodsSampleForTestsSize = arraysize(kMethodsSampleForTests);
+
+ if (env->RegisterNatives(g_SampleForTests_clazz,
+ kMethodsSampleForTests,
+ kMethodsSampleForTestsSize) < 0) {
+ LOG(ERROR) << "RegisterNatives failed in " << __FILE__;
+ return false;
+ }
+
+ return true;
+}
+} // namespace android
+} // namespace base
+
+#endif // org_chromium_example_jni_generator_SampleForTests_JNI
diff --git a/src/base/android/jni_generator/jni_generator.gyp b/src/base/android/jni_generator/jni_generator.gyp
new file mode 100644
index 0000000..dc32d22
--- /dev/null
+++ b/src/base/android/jni_generator/jni_generator.gyp
@@ -0,0 +1,55 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'jni_generator_py_tests',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'action_name': 'run_jni_generator_py_tests',
+ 'inputs': [
+ 'jni_generator.py',
+ 'jni_generator_tests.py',
+ 'SampleForTests.java',
+ 'golden_sample_for_tests_jni.h',
+ ],
+ 'outputs': [
+ '',
+ ],
+ 'action': [
+ 'python', 'jni_generator_tests.py',
+ ],
+ },
+ ],
+ },
+ {
+ 'target_name': 'jni_sample_header',
+ 'type': 'none',
+ 'sources': [
+ 'SampleForTests.java',
+ ],
+ 'variables': {
+ 'jni_gen_dir': 'base',
+ },
+ 'includes': [ '../../../build/jni_generator.gypi' ],
+ },
+ {
+ 'target_name': 'jni_generator_tests',
+ 'type': 'executable',
+ 'dependencies': [
+ '../../base.gyp:test_support_base',
+ 'jni_generator_py_tests',
+ 'jni_sample_header',
+ ],
+ 'include_dirs': [
+ '<(SHARED_INTERMEDIATE_DIR)/base',
+ ],
+ 'sources': [
+ 'sample_for_tests.cc',
+ ],
+ },
+ ],
+}
diff --git a/src/base/android/jni_generator/jni_generator.py b/src/base/android/jni_generator/jni_generator.py
new file mode 100755
index 0000000..18312c6
--- /dev/null
+++ b/src/base/android/jni_generator/jni_generator.py
@@ -0,0 +1,1005 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Extracts native methods from a Java file and generates the JNI bindings.
+If you change this, please run and update the tests."""
+
+import collections
+import optparse
+import os
+import re
+import string
+from string import Template
+import subprocess
+import sys
+import textwrap
+import zipfile
+
+
+class ParseError(Exception):
+ """Exception thrown when we can't parse the input file."""
+
+ def __init__(self, description, *context_lines):
+ Exception.__init__(self)
+ self.description = description
+ self.context_lines = context_lines
+
+ def __str__(self):
+ context = '\n'.join(self.context_lines)
+ return '***\nERROR: %s\n\n%s\n***' % (self.description, context)
+
+
+class Param(object):
+ """Describes a param for a method, either java or native."""
+
+ def __init__(self, **kwargs):
+ self.datatype = kwargs['datatype']
+ self.name = kwargs['name']
+
+
+class NativeMethod(object):
+ """Describes a C/C++ method that is called by Java code"""
+
+ def __init__(self, **kwargs):
+ self.static = kwargs['static']
+ self.java_class_name = kwargs['java_class_name']
+ self.return_type = kwargs['return_type']
+ self.name = kwargs['name']
+ self.params = kwargs['params']
+ if self.params:
+ assert type(self.params) is list
+ assert type(self.params[0]) is Param
+ if (self.params and
+ self.params[0].datatype == 'int' and
+ self.params[0].name.startswith('native')):
+ self.type = 'method'
+ self.p0_type = self.params[0].name[len('native'):]
+ if kwargs.get('native_class_name'):
+ self.p0_type = kwargs['native_class_name']
+ else:
+ self.type = 'function'
+ self.method_id_var_name = kwargs.get('method_id_var_name', None)
+
+
+class CalledByNative(object):
+ """Describes a java method exported to c/c++"""
+
+ def __init__(self, **kwargs):
+ self.system_class = kwargs['system_class']
+ self.unchecked = kwargs['unchecked']
+ self.static = kwargs['static']
+ self.java_class_name = kwargs['java_class_name']
+ self.return_type = kwargs['return_type']
+ self.name = kwargs['name']
+ self.params = kwargs['params']
+ self.method_id_var_name = kwargs.get('method_id_var_name', None)
+ self.is_constructor = kwargs.get('is_constructor', False)
+ self.env_call = GetEnvCall(self.is_constructor, self.static,
+ self.return_type)
+ self.static_cast = GetStaticCastForReturnType(self.return_type)
+
+
+def JavaDataTypeToC(java_type):
+ """Returns a C datatype for the given java type."""
+ java_pod_type_map = {
+ 'int': 'jint',
+ 'byte': 'jbyte',
+ 'boolean': 'jboolean',
+ 'long': 'jlong',
+ 'double': 'jdouble',
+ 'float': 'jfloat',
+ }
+ java_type_map = {
+ 'void': 'void',
+ 'String': 'jstring',
+ 'java/lang/String': 'jstring',
+ 'Class': 'jclass',
+ 'java/lang/Class': 'jclass',
+ }
+
+ if java_type in java_pod_type_map:
+ return java_pod_type_map[java_type]
+ elif java_type in java_type_map:
+ return java_type_map[java_type]
+ elif java_type.endswith('[]'):
+ if java_type[:-2] in java_pod_type_map:
+ return java_pod_type_map[java_type[:-2]] + 'Array'
+ return 'jobjectArray'
+ else:
+ return 'jobject'
+
+
+class JniParams(object):
+ _imports = []
+ _fully_qualified_class = ''
+ _package = ''
+ _inner_classes = []
+
+ @staticmethod
+ def SetFullyQualifiedClass(fully_qualified_class):
+ JniParams._fully_qualified_class = 'L' + fully_qualified_class
+ JniParams._package = '/'.join(fully_qualified_class.split('/')[:-1])
+
+ @staticmethod
+ def ExtractImportsAndInnerClasses(contents):
+ contents = contents.replace('\n', '')
+ re_import = re.compile(r'import.*?(?P<class>\S*?);')
+ for match in re.finditer(re_import, contents):
+ JniParams._imports += ['L' + match.group('class').replace('.', '/')]
+
+ re_inner = re.compile(r'(class|interface)\s+?(?P<name>\w+?)\W')
+ for match in re.finditer(re_inner, contents):
+ inner = match.group('name')
+ if not JniParams._fully_qualified_class.endswith(inner):
+ JniParams._inner_classes += [JniParams._fully_qualified_class + '$' +
+ inner]
+
+ @staticmethod
+ def JavaToJni(param):
+ """Converts a java param into a JNI signature type."""
+ pod_param_map = {
+ 'int': 'I',
+ 'boolean': 'Z',
+ 'long': 'J',
+ 'double': 'D',
+ 'float': 'F',
+ 'byte': 'B',
+ 'void': 'V',
+ }
+ object_param_list = [
+ 'Ljava/lang/Boolean',
+ 'Ljava/lang/Integer',
+ 'Ljava/lang/Long',
+ 'Ljava/lang/Object',
+ 'Ljava/lang/String',
+ 'Ljava/lang/Class',
+ ]
+ if param == 'byte[][]':
+ return '[[B'
+ prefix = ''
+ # Array?
+ if param[-2:] == '[]':
+ prefix = '['
+ param = param[:-2]
+ # Generic?
+ if '<' in param:
+ param = param[:param.index('<')]
+ if param in pod_param_map:
+ return prefix + pod_param_map[param]
+ if '/' in param:
+ # Coming from javap, use the fully qualified param directly.
+ return 'L' + param + ';'
+ for qualified_name in (object_param_list +
+ [JniParams._fully_qualified_class] +
+ JniParams._inner_classes):
+ if (qualified_name.endswith('/' + param) or
+ qualified_name.endswith('$' + param.replace('.', '$')) or
+ qualified_name == 'L' + param):
+ return prefix + qualified_name + ';'
+
+ # Is it from an import? (e.g. referecing Class from import pkg.Class;
+ # note that referencing an inner class Inner from import pkg.Class.Inner
+ # is not supported).
+ for qualified_name in JniParams._imports:
+ if qualified_name.endswith('/' + param):
+ # Ensure it's not an inner class.
+ components = qualified_name.split('/')
+ if len(components) > 2 and components[-2][0].isupper():
+ raise SyntaxError('Inner class (%s) can not be imported '
+ 'and used by JNI (%s). Please import the outer '
+ 'class and use Outer.Inner instead.' %
+ (qualified_name, param))
+ return prefix + qualified_name + ';'
+
+ # Is it an inner class from an outer class import? (e.g. referencing
+ # Class.Inner from import pkg.Class).
+ if '.' in param:
+ components = param.split('.')
+ outer = '/'.join(components[:-1])
+ inner = components[-1]
+ for qualified_name in JniParams._imports:
+ if qualified_name.endswith('/' + outer):
+ return prefix + qualified_name + '$' + inner
+
+ # Type not found, falling back to same package as this class.
+ return prefix + 'L' + JniParams._package + '/' + param + ';'
+
+ @staticmethod
+ def Signature(params, returns, wrap):
+ """Returns the JNI signature for the given datatypes."""
+ items = ['(']
+ items += [JniParams.JavaToJni(param.datatype) for param in params]
+ items += [')']
+ items += [JniParams.JavaToJni(returns)]
+ if wrap:
+ return '\n' + '\n'.join(['"' + item + '"' for item in items])
+ else:
+ return '"' + ''.join(items) + '"'
+
+ @staticmethod
+ def Parse(params):
+ """Parses the params into a list of Param objects."""
+ if not params:
+ return []
+ ret = []
+ for p in [p.strip() for p in params.split(',')]:
+ items = p.split(' ')
+ if 'final' in items:
+ items.remove('final')
+ param = Param(
+ datatype=items[0],
+ name=(items[1] if len(items) > 1 else 'p%s' % len(ret)),
+ )
+ ret += [param]
+ return ret
+
+
+def ExtractJNINamespace(contents):
+ re_jni_namespace = re.compile('.*?@JNINamespace\("(.*?)"\)')
+ m = re.findall(re_jni_namespace, contents)
+ if not m:
+ return ''
+ return m[0]
+
+
+def ExtractFullyQualifiedJavaClassName(java_file_name, contents):
+ re_package = re.compile('.*?package (.*?);')
+ matches = re.findall(re_package, contents)
+ if not matches:
+ raise SyntaxError('Unable to find "package" line in %s' % java_file_name)
+ return (matches[0].replace('.', '/') + '/' +
+ os.path.splitext(os.path.basename(java_file_name))[0])
+
+
+def ExtractNatives(contents):
+ """Returns a list of dict containing information about a native method."""
+ contents = contents.replace('\n', '')
+ natives = []
+ re_native = re.compile(r'(@NativeClassQualifiedName'
+ '\(\"(?P<native_class_name>.*?)\"\))?\s*'
+ '(@NativeCall(\(\"(?P<java_class_name>.*?)\"\)))?\s*'
+ '(?P<qualifiers>\w+\s\w+|\w+|\s+)\s*?native '
+ '(?P<return>\S*?) '
+ '(?P<name>\w+?)\((?P<params>.*?)\);')
+ for match in re.finditer(re_native, contents):
+ native = NativeMethod(
+ static='static' in match.group('qualifiers'),
+ java_class_name=match.group('java_class_name'),
+ native_class_name=match.group('native_class_name'),
+ return_type=match.group('return'),
+ name=match.group('name').replace('native', ''),
+ params=JniParams.Parse(match.group('params')))
+ natives += [native]
+ return natives
+
+
+def GetStaticCastForReturnType(return_type):
+ if return_type in ['String', 'java/lang/String']:
+ return 'jstring'
+ elif return_type.endswith('[]'):
+ return 'jobjectArray'
+ return None
+
+
+def GetEnvCall(is_constructor, is_static, return_type):
+ """Maps the types availabe via env->Call__Method."""
+ if is_constructor:
+ return 'NewObject'
+ env_call_map = {'boolean': 'Boolean',
+ 'byte': 'Byte',
+ 'char': 'Char',
+ 'short': 'Short',
+ 'int': 'Int',
+ 'long': 'Long',
+ 'float': 'Float',
+ 'void': 'Void',
+ 'double': 'Double',
+ 'Object': 'Object',
+ }
+ call = env_call_map.get(return_type, 'Object')
+ if is_static:
+ call = 'Static' + call
+ return 'Call' + call + 'Method'
+
+
+def GetMangledParam(datatype):
+ """Returns a mangled identifier for the datatype."""
+ if len(datatype) <= 2:
+ return datatype.replace('[', 'A')
+ ret = ''
+ for i in range(1, len(datatype)):
+ c = datatype[i]
+ if c == '[':
+ ret += 'A'
+ elif c.isupper() or datatype[i - 1] in ['/', 'L']:
+ ret += c.upper()
+ return ret
+
+
+def GetMangledMethodName(name, params, return_type):
+ """Returns a mangled method name for the given signature.
+
+ The returned name can be used as a C identifier and will be unique for all
+ valid overloads of the same method.
+
+ Args:
+ name: string.
+ params: list of Param.
+ return_type: string.
+
+ Returns:
+ A mangled name.
+ """
+ mangled_items = []
+ for datatype in [return_type] + [x.datatype for x in params]:
+ mangled_items += [GetMangledParam(JniParams.JavaToJni(datatype))]
+ mangled_name = name + '_'.join(mangled_items)
+ assert re.match(r'[0-9a-zA-Z_]+', mangled_name)
+ return mangled_name
+
+
+def MangleCalledByNatives(called_by_natives):
+ """Mangles all the overloads from the call_by_natives list."""
+ method_counts = collections.defaultdict(
+ lambda: collections.defaultdict(lambda: 0))
+ for called_by_native in called_by_natives:
+ java_class_name = called_by_native.java_class_name
+ name = called_by_native.name
+ method_counts[java_class_name][name] += 1
+ for called_by_native in called_by_natives:
+ java_class_name = called_by_native.java_class_name
+ method_name = called_by_native.name
+ method_id_var_name = method_name
+ if method_counts[java_class_name][method_name] > 1:
+ method_id_var_name = GetMangledMethodName(method_name,
+ called_by_native.params,
+ called_by_native.return_type)
+ called_by_native.method_id_var_name = method_id_var_name
+ return called_by_natives
+
+
+# Regex to match the JNI return types that should be included in a
+# ScopedJavaLocalRef.
+RE_SCOPED_JNI_RETURN_TYPES = re.compile('jobject|jclass|jstring|.*Array')
+
+# Regex to match a string like "@CalledByNative public void foo(int bar)".
+RE_CALLED_BY_NATIVE = re.compile(
+ '@CalledByNative(?P<Unchecked>(Unchecked)*?)(?:\("(?P<annotation>.*)"\))?'
+ '\s+(?P<prefix>[\w ]*?)'
+ '\s*(?P<return_type>\w+)'
+ '\s+(?P<name>\w+)'
+ '\s*\((?P<params>[^\)]*)\)')
+
+
+def ExtractCalledByNatives(contents):
+ """Parses all methods annotated with @CalledByNative.
+
+ Args:
+ contents: the contents of the java file.
+
+ Returns:
+ A list of dict with information about the annotated methods.
+ TODO(bulach): return a CalledByNative object.
+
+ Raises:
+ ParseError: if unable to parse.
+ """
+ called_by_natives = []
+ for match in re.finditer(RE_CALLED_BY_NATIVE, contents):
+ called_by_natives += [CalledByNative(
+ system_class=False,
+ unchecked='Unchecked' in match.group('Unchecked'),
+ static='static' in match.group('prefix'),
+ java_class_name=match.group('annotation') or '',
+ return_type=match.group('return_type'),
+ name=match.group('name'),
+ params=JniParams.Parse(match.group('params')))]
+ # Check for any @CalledByNative occurrences that weren't matched.
+ unmatched_lines = re.sub(RE_CALLED_BY_NATIVE, '', contents).split('\n')
+ for line1, line2 in zip(unmatched_lines, unmatched_lines[1:]):
+ if '@CalledByNative' in line1:
+ raise ParseError('could not parse @CalledByNative method signature',
+ line1, line2)
+ return MangleCalledByNatives(called_by_natives)
+
+
+class JNIFromJavaP(object):
+ """Uses 'javap' to parse a .class file and generate the JNI header file."""
+
+ def __init__(self, contents, namespace):
+ self.contents = contents
+ self.namespace = namespace
+ self.fully_qualified_class = re.match('.*?class (?P<class_name>.*?) ',
+ contents[1]).group('class_name')
+ self.fully_qualified_class = self.fully_qualified_class.replace('.', '/')
+ JniParams.SetFullyQualifiedClass(self.fully_qualified_class)
+ self.java_class_name = self.fully_qualified_class.split('/')[-1]
+ if not self.namespace:
+ self.namespace = 'JNI_' + self.java_class_name
+ re_method = re.compile('(?P<prefix>.*?)(?P<return_type>\S+?) (?P<name>\w+?)'
+ '\((?P<params>.*?)\)')
+ self.called_by_natives = []
+ for content in contents[2:]:
+ match = re.match(re_method, content)
+ if not match:
+ continue
+ self.called_by_natives += [CalledByNative(
+ system_class=True,
+ unchecked=False,
+ static='static' in match.group('prefix'),
+ java_class_name='',
+ return_type=match.group('return_type').replace('.', '/'),
+ name=match.group('name'),
+ params=JniParams.Parse(match.group('params').replace('.', '/')))]
+ re_constructor = re.compile('.*? public ' +
+ self.fully_qualified_class.replace('/', '.') +
+ '\((?P<params>.*?)\)')
+ for content in contents[2:]:
+ match = re.match(re_constructor, content)
+ if not match:
+ continue
+ self.called_by_natives += [CalledByNative(
+ system_class=True,
+ unchecked=False,
+ static=False,
+ java_class_name='',
+ return_type=self.fully_qualified_class,
+ name='Constructor',
+ params=JniParams.Parse(match.group('params').replace('.', '/')),
+ is_constructor=True)]
+ self.called_by_natives = MangleCalledByNatives(self.called_by_natives)
+ self.inl_header_file_generator = InlHeaderFileGenerator(
+ self.namespace, self.fully_qualified_class, [], self.called_by_natives)
+
+ def GetContent(self):
+ return self.inl_header_file_generator.GetContent()
+
+ @staticmethod
+ def CreateFromClass(class_file, namespace):
+ class_name = os.path.splitext(os.path.basename(class_file))[0]
+ p = subprocess.Popen(args=['javap', class_name],
+ cwd=os.path.dirname(class_file),
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ stdout, _ = p.communicate()
+ jni_from_javap = JNIFromJavaP(stdout.split('\n'), namespace)
+ return jni_from_javap
+
+
+class JNIFromJavaSource(object):
+ """Uses the given java source file to generate the JNI header file."""
+
+ def __init__(self, contents, fully_qualified_class):
+ contents = self._RemoveComments(contents)
+ JniParams.SetFullyQualifiedClass(fully_qualified_class)
+ JniParams.ExtractImportsAndInnerClasses(contents)
+ jni_namespace = ExtractJNINamespace(contents)
+ natives = ExtractNatives(contents)
+ called_by_natives = ExtractCalledByNatives(contents)
+ if len(natives) == 0 and len(called_by_natives) == 0:
+ raise SyntaxError('Unable to find any JNI methods for %s.' %
+ fully_qualified_class)
+ inl_header_file_generator = InlHeaderFileGenerator(
+ jni_namespace, fully_qualified_class, natives, called_by_natives)
+ self.content = inl_header_file_generator.GetContent()
+
+ def _RemoveComments(self, contents):
+ # We need to support both inline and block comments, and we need to handle
+ # strings that contain '//' or '/*'. Rather than trying to do all that with
+ # regexps, we just pipe the contents through the C preprocessor. We tell cpp
+ # the file has already been preprocessed, so it just removes comments and
+ # doesn't try to parse #include, #pragma etc.
+ #
+ # TODO(husky): This is a bit hacky. It would be cleaner to use a real Java
+ # parser. Maybe we could ditch JNIFromJavaSource and just always use
+ # JNIFromJavaP; or maybe we could rewrite this script in Java and use APT.
+ # http://code.google.com/p/chromium/issues/detail?id=138941
+ p = subprocess.Popen(args=['cpp', '-fpreprocessed'],
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ stdout, _ = p.communicate(contents)
+ return stdout
+
+ def GetContent(self):
+ return self.content
+
+ @staticmethod
+ def CreateFromFile(java_file_name):
+ contents = file(java_file_name).read()
+ fully_qualified_class = ExtractFullyQualifiedJavaClassName(java_file_name,
+ contents)
+ return JNIFromJavaSource(contents, fully_qualified_class)
+
+
+class InlHeaderFileGenerator(object):
+ """Generates an inline header file for JNI integration."""
+
+ def __init__(self, namespace, fully_qualified_class, natives,
+ called_by_natives):
+ self.namespace = namespace
+ self.fully_qualified_class = fully_qualified_class
+ self.class_name = self.fully_qualified_class.split('/')[-1]
+ self.natives = natives
+ self.called_by_natives = called_by_natives
+ self.header_guard = fully_qualified_class.replace('/', '_') + '_JNI'
+
+ def GetContent(self):
+ """Returns the content of the JNI binding file."""
+ template = Template("""\
+// Copyright (c) 2012 The Chromium Authors. 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 autogenerated by
+// ${SCRIPT_NAME}
+// For
+// ${FULLY_QUALIFIED_CLASS}
+
+#ifndef ${HEADER_GUARD}
+#define ${HEADER_GUARD}
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+using base::android::ScopedJavaLocalRef;
+
+// Step 1: forward declarations.
+namespace {
+$CLASS_PATH_DEFINITIONS
+} // namespace
+
+$OPEN_NAMESPACE
+$FORWARD_DECLARATIONS
+
+// Step 2: method stubs.
+$METHOD_STUBS
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+$REGISTER_NATIVES_IMPL
+ return true;
+}
+$CLOSE_NAMESPACE
+#endif // ${HEADER_GUARD}
+""")
+ script_components = os.path.abspath(sys.argv[0]).split(os.path.sep)
+ base_index = script_components.index('base')
+ script_name = os.sep.join(script_components[base_index:])
+ values = {
+ 'SCRIPT_NAME': script_name,
+ 'FULLY_QUALIFIED_CLASS': self.fully_qualified_class,
+ 'CLASS_PATH_DEFINITIONS': self.GetClassPathDefinitionsString(),
+ 'FORWARD_DECLARATIONS': self.GetForwardDeclarationsString(),
+ 'METHOD_STUBS': self.GetMethodStubsString(),
+ 'OPEN_NAMESPACE': self.GetOpenNamespaceString(),
+ 'REGISTER_NATIVES_IMPL': self.GetRegisterNativesImplString(),
+ 'CLOSE_NAMESPACE': self.GetCloseNamespaceString(),
+ 'HEADER_GUARD': self.header_guard,
+ }
+ return WrapOutput(template.substitute(values))
+
+ def GetClassPathDefinitionsString(self):
+ ret = []
+ ret += [self.GetClassPathDefinitions()]
+ return '\n'.join(ret)
+
+ def GetForwardDeclarationsString(self):
+ ret = []
+ for native in self.natives:
+ if native.type != 'method':
+ ret += [self.GetForwardDeclaration(native)]
+ return '\n'.join(ret)
+
+ def GetMethodStubsString(self):
+ ret = []
+ for native in self.natives:
+ if native.type == 'method':
+ ret += [self.GetNativeMethodStub(native)]
+ for called_by_native in self.called_by_natives:
+ ret += [self.GetCalledByNativeMethodStub(called_by_native)]
+ return '\n'.join(ret)
+
+ def GetKMethodsString(self, clazz):
+ ret = []
+ for native in self.natives:
+ if (native.java_class_name == clazz or
+ (not native.java_class_name and clazz == self.class_name)):
+ ret += [self.GetKMethodArrayEntry(native)]
+ return '\n'.join(ret)
+
+ def GetRegisterNativesImplString(self):
+ """Returns the implementation for RegisterNatives."""
+ template = Template("""\
+ static const JNINativeMethod kMethods${JAVA_CLASS}[] = {
+${KMETHODS}
+ };
+ const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS});
+
+ if (env->RegisterNatives(g_${JAVA_CLASS}_clazz,
+ kMethods${JAVA_CLASS},
+ kMethods${JAVA_CLASS}Size) < 0) {
+ LOG(ERROR) << "RegisterNatives failed in " << __FILE__;
+ return false;
+ }
+""")
+ ret = [self.GetFindClasses()]
+ all_classes = self.GetUniqueClasses(self.natives)
+ all_classes[self.class_name] = self.fully_qualified_class
+ for clazz in all_classes:
+ kmethods = self.GetKMethodsString(clazz)
+ if kmethods:
+ values = {'JAVA_CLASS': clazz,
+ 'KMETHODS': kmethods}
+ ret += [template.substitute(values)]
+ if not ret: return ''
+ return '\n' + '\n'.join(ret)
+
+ def GetOpenNamespaceString(self):
+ if self.namespace:
+ all_namespaces = ['namespace %s {' % ns
+ for ns in self.namespace.split('::')]
+ return '\n'.join(all_namespaces)
+ return ''
+
+ def GetCloseNamespaceString(self):
+ if self.namespace:
+ all_namespaces = ['} // namespace %s' % ns
+ for ns in self.namespace.split('::')]
+ all_namespaces.reverse()
+ return '\n'.join(all_namespaces) + '\n'
+ return ''
+
+ def GetJNIFirstParam(self, native):
+ ret = []
+ if native.type == 'method':
+ ret = ['jobject obj']
+ elif native.type == 'function':
+ if native.static:
+ ret = ['jclass clazz']
+ else:
+ ret = ['jobject obj']
+ return ret
+
+ def GetParamsInDeclaration(self, native):
+ """Returns the params for the stub declaration.
+
+ Args:
+ native: the native dictionary describing the method.
+
+ Returns:
+ A string containing the params.
+ """
+ return ',\n '.join(self.GetJNIFirstParam(native) +
+ [JavaDataTypeToC(param.datatype) + ' ' +
+ param.name
+ for param in native.params])
+
+ def GetCalledByNativeParamsInDeclaration(self, called_by_native):
+ return ',\n '.join([JavaDataTypeToC(param.datatype) + ' ' +
+ param.name
+ for param in called_by_native.params])
+
+ def GetForwardDeclaration(self, native):
+ template = Template("""
+static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS});
+""")
+ values = {'RETURN': JavaDataTypeToC(native.return_type),
+ 'NAME': native.name,
+ 'PARAMS': self.GetParamsInDeclaration(native)}
+ return template.substitute(values)
+
+ def GetNativeMethodStub(self, native):
+ """Returns stubs for native methods."""
+ template = Template("""\
+static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) {
+ DCHECK(${PARAM0_NAME}) << "${NAME}";
+ ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME});
+ return native->${NAME}(env, obj${PARAMS_IN_CALL})${POST_CALL};
+}
+""")
+ params_for_call = ', '.join(p.name for p in native.params[1:])
+ if params_for_call:
+ params_for_call = ', ' + params_for_call
+
+ return_type = JavaDataTypeToC(native.return_type)
+ if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type):
+ scoped_return_type = 'ScopedJavaLocalRef<' + return_type + '>'
+ post_call = '.Release()'
+ else:
+ scoped_return_type = return_type
+ post_call = ''
+ values = {
+ 'RETURN': return_type,
+ 'SCOPED_RETURN': scoped_return_type,
+ 'NAME': native.name,
+ 'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native),
+ 'PARAM0_NAME': native.params[0].name,
+ 'P0_TYPE': native.p0_type,
+ 'PARAMS_IN_CALL': params_for_call,
+ 'POST_CALL': post_call
+ }
+ return template.substitute(values)
+
+ def GetCalledByNativeMethodStub(self, called_by_native):
+ """Returns a string."""
+ function_signature_template = Template("""\
+static ${RETURN_TYPE} Java_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}(\
+JNIEnv* env${FIRST_PARAM_IN_DECLARATION}${PARAMS_IN_DECLARATION})""")
+ function_header_template = Template("""\
+${FUNCTION_SIGNATURE} {""")
+ function_header_with_unused_template = Template("""\
+${FUNCTION_SIGNATURE} __attribute__ ((unused));
+${FUNCTION_SIGNATURE} {""")
+ template = Template("""
+static base::subtle::AtomicWord g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = 0;
+${FUNCTION_HEADER}
+ /* Must call RegisterNativesImpl() */
+ DCHECK(g_${JAVA_CLASS}_clazz);
+ jmethodID method_id =
+ ${GET_METHOD_ID_IMPL}
+ ${RETURN_DECLARATION}
+ ${PRE_CALL}env->${ENV_CALL}(${FIRST_PARAM_IN_CALL},
+ method_id${PARAMS_IN_CALL})${POST_CALL};
+ ${CHECK_EXCEPTION}
+ ${RETURN_CLAUSE}
+}""")
+ if called_by_native.static or called_by_native.is_constructor:
+ first_param_in_declaration = ''
+ first_param_in_call = ('g_%s_clazz' %
+ (called_by_native.java_class_name or
+ self.class_name))
+ else:
+ first_param_in_declaration = ', jobject obj'
+ first_param_in_call = 'obj'
+ params_in_declaration = self.GetCalledByNativeParamsInDeclaration(
+ called_by_native)
+ if params_in_declaration:
+ params_in_declaration = ', ' + params_in_declaration
+ params_for_call = ', '.join(param.name
+ for param in called_by_native.params)
+ if params_for_call:
+ params_for_call = ', ' + params_for_call
+ pre_call = ''
+ post_call = ''
+ if called_by_native.static_cast:
+ pre_call = 'static_cast<%s>(' % called_by_native.static_cast
+ post_call = ')'
+ check_exception = ''
+ if not called_by_native.unchecked:
+ check_exception = 'base::android::CheckException(env);'
+ return_type = JavaDataTypeToC(called_by_native.return_type)
+ return_declaration = ''
+ return_clause = ''
+ if return_type != 'void':
+ pre_call = ' ' + pre_call
+ return_declaration = return_type + ' ret ='
+ if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type):
+ return_type = 'ScopedJavaLocalRef<' + return_type + '>'
+ return_clause = 'return ' + return_type + '(env, ret);'
+ else:
+ return_clause = 'return ret;'
+ values = {
+ 'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
+ 'METHOD': called_by_native.name,
+ 'RETURN_TYPE': return_type,
+ 'RETURN_DECLARATION': return_declaration,
+ 'RETURN_CLAUSE': return_clause,
+ 'FIRST_PARAM_IN_DECLARATION': first_param_in_declaration,
+ 'PARAMS_IN_DECLARATION': params_in_declaration,
+ 'STATIC': 'Static' if called_by_native.static else '',
+ 'PRE_CALL': pre_call,
+ 'POST_CALL': post_call,
+ 'ENV_CALL': called_by_native.env_call,
+ 'FIRST_PARAM_IN_CALL': first_param_in_call,
+ 'PARAMS_IN_CALL': params_for_call,
+ 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
+ 'CHECK_EXCEPTION': check_exception,
+ 'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native)
+ }
+ values['FUNCTION_SIGNATURE'] = (
+ function_signature_template.substitute(values))
+ if called_by_native.system_class:
+ values['FUNCTION_HEADER'] = (
+ function_header_with_unused_template.substitute(values))
+ else:
+ values['FUNCTION_HEADER'] = function_header_template.substitute(values)
+ return template.substitute(values)
+
+ def GetKMethodArrayEntry(self, native):
+ template = Template("""\
+ { "native${NAME}", ${JNI_SIGNATURE}, reinterpret_cast<void*>(${NAME}) },""")
+ values = {'NAME': native.name,
+ 'JNI_SIGNATURE': JniParams.Signature(native.params,
+ native.return_type,
+ True)}
+ return template.substitute(values)
+
+ def GetUniqueClasses(self, origin):
+ ret = {self.class_name: self.fully_qualified_class}
+ for entry in origin:
+ class_name = self.class_name
+ jni_class_path = self.fully_qualified_class
+ if entry.java_class_name:
+ class_name = entry.java_class_name
+ jni_class_path = self.fully_qualified_class + '$' + class_name
+ ret[class_name] = jni_class_path
+ return ret
+
+ def GetClassPathDefinitions(self):
+ """Returns the ClassPath constants."""
+ ret = []
+ template = Template("""\
+const char k${JAVA_CLASS}ClassPath[] = "${JNI_CLASS_PATH}";""")
+ native_classes = self.GetUniqueClasses(self.natives)
+ called_by_native_classes = self.GetUniqueClasses(self.called_by_natives)
+ all_classes = native_classes
+ all_classes.update(called_by_native_classes)
+ for clazz in all_classes:
+ values = {
+ 'JAVA_CLASS': clazz,
+ 'JNI_CLASS_PATH': all_classes[clazz],
+ }
+ ret += [template.substitute(values)]
+ ret += ''
+ for clazz in called_by_native_classes:
+ template = Template("""\
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_${JAVA_CLASS}_clazz = NULL;""")
+ values = {
+ 'JAVA_CLASS': clazz,
+ }
+ ret += [template.substitute(values)]
+ return '\n'.join(ret)
+
+ def GetFindClasses(self):
+ """Returns the imlementation of FindClass for all known classes."""
+ template = Template("""\
+ g_${JAVA_CLASS}_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+ base::android::GetUnscopedClass(env, k${JAVA_CLASS}ClassPath)));""")
+ ret = []
+ for clazz in self.GetUniqueClasses(self.called_by_natives):
+ values = {'JAVA_CLASS': clazz}
+ ret += [template.substitute(values)]
+ return '\n'.join(ret)
+
+ def GetMethodIDImpl(self, called_by_native):
+ """Returns the implementation of GetMethodID."""
+ template = Template("""\
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_${STATIC}>(
+ env, g_${JAVA_CLASS}_clazz,
+ "${JNI_NAME}",
+ ${JNI_SIGNATURE},
+ &g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME});
+""")
+ jni_name = called_by_native.name
+ jni_return_type = called_by_native.return_type
+ if called_by_native.is_constructor:
+ jni_name = '<init>'
+ jni_return_type = 'void'
+ values = {
+ 'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
+ 'JNI_NAME': jni_name,
+ 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
+ 'STATIC': 'STATIC' if called_by_native.static else 'INSTANCE',
+ 'JNI_SIGNATURE': JniParams.Signature(called_by_native.params,
+ jni_return_type,
+ True)
+ }
+ return template.substitute(values)
+
+
+def WrapOutput(output):
+ ret = []
+ for line in output.splitlines():
+ # Do not wrap lines under 80 characters or preprocessor directives.
+ if len(line) < 80 or line.lstrip()[:1] == '#':
+ stripped = line.rstrip()
+ if len(ret) == 0 or len(ret[-1]) or len(stripped):
+ ret.append(stripped)
+ else:
+ first_line_indent = ' ' * (len(line) - len(line.lstrip()))
+ subsequent_indent = first_line_indent + ' ' * 4
+ if line.startswith('//'):
+ subsequent_indent = '//' + subsequent_indent
+ wrapper = textwrap.TextWrapper(width=80,
+ subsequent_indent=subsequent_indent,
+ break_long_words=False)
+ ret += [wrapped.rstrip() for wrapped in wrapper.wrap(line)]
+ ret += ['']
+ return '\n'.join(ret)
+
+
+def ExtractJarInputFile(jar_file, input_file, out_dir):
+ """Extracts input file from jar and returns the filename.
+
+ The input file is extracted to the same directory that the generated jni
+ headers will be placed in. This is passed as an argument to script.
+
+ Args:
+ jar_file: the jar file containing the input files to extract.
+ input_files: the list of files to extract from the jar file.
+ out_dir: the name of the directories to extract to.
+
+ Returns:
+ the name of extracted input file.
+ """
+ jar_file = zipfile.ZipFile(jar_file)
+
+ out_dir = os.path.join(out_dir, os.path.dirname(input_file))
+ if not os.path.exists(out_dir):
+ os.makedirs(out_dir)
+ extracted_file_name = os.path.join(out_dir, os.path.basename(input_file))
+ with open(extracted_file_name, 'w') as outfile:
+ outfile.write(jar_file.read(input_file))
+
+ return extracted_file_name
+
+
+def GenerateJNIHeader(input_file, output_file, namespace):
+ try:
+ if os.path.splitext(input_file)[1] == '.class':
+ jni_from_javap = JNIFromJavaP.CreateFromClass(input_file, namespace)
+ content = jni_from_javap.GetContent()
+ else:
+ jni_from_java_source = JNIFromJavaSource.CreateFromFile(input_file)
+ content = jni_from_java_source.GetContent()
+ except ParseError, e:
+ print e
+ sys.exit(1)
+ if output_file:
+ if not os.path.exists(os.path.dirname(os.path.abspath(output_file))):
+ os.makedirs(os.path.dirname(os.path.abspath(output_file)))
+ with file(output_file, 'w') as f:
+ f.write(content)
+ else:
+ print output
+
+
+def main(argv):
+ usage = """usage: %prog [OPTIONS]
+This script will parse the given java source code extracting the native
+declarations and print the header file to stdout (or a file).
+See SampleForTests.java for more details.
+ """
+ option_parser = optparse.OptionParser(usage=usage)
+ option_parser.add_option('-j', dest='jar_file',
+ help='Extract the list of input files from'
+ ' a specified jar file.'
+ ' Uses javap to extract the methods from a'
+ ' pre-compiled class. --input should point'
+ ' to pre-compiled Java .class files.')
+ option_parser.add_option('-n', dest='namespace',
+ help='Uses as a namespace in the generated header,'
+ ' instead of the javap class name.')
+ option_parser.add_option('--input_file',
+ help='Single input file name. The output file name '
+ 'will be derived from it. Must be used with '
+ '--output_dir.')
+ option_parser.add_option('--output_dir',
+ help='The output directory. Must be used with '
+ '--input')
+ options, args = option_parser.parse_args(argv)
+ if options.jar_file:
+ input_file = ExtractJarInputFile(options.jar_file, options.input_file,
+ options.output_dir)
+ else:
+ input_file = options.input_file
+ output_file = None
+ if options.output_dir:
+ root_name = os.path.splitext(os.path.basename(input_file))[0]
+ output_file = os.path.join(options.output_dir, root_name) + '_jni.h'
+ GenerateJNIHeader(input_file, output_file, options.namespace)
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))
diff --git a/src/base/android/jni_generator/jni_generator_tests.py b/src/base/android/jni_generator/jni_generator_tests.py
new file mode 100755
index 0000000..5863977
--- /dev/null
+++ b/src/base/android/jni_generator/jni_generator_tests.py
@@ -0,0 +1,1590 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Tests for jni_generator.py.
+
+This test suite contains various tests for the JNI generator.
+It exercises the low-level parser all the way up to the
+code generator and ensures the output matches a golden
+file.
+"""
+
+import difflib
+import os
+import sys
+import unittest
+import jni_generator
+from jni_generator import CalledByNative, NativeMethod, Param
+
+
+class TestGenerator(unittest.TestCase):
+ def assertObjEquals(self, first, second):
+ dict_first = first.__dict__
+ dict_second = second.__dict__
+ self.assertEquals(dict_first.keys(), dict_second.keys())
+ for key, value in dict_first.iteritems():
+ if (type(value) is list and len(value) and
+ isinstance(type(value[0]), object)):
+ self.assertListEquals(value, second.__getattribute__(key))
+ else:
+ actual = second.__getattribute__(key)
+ self.assertEquals(value, actual,
+ 'Key ' + key + ': ' + str(value) + '!=' + str(actual))
+
+ def assertListEquals(self, first, second):
+ self.assertEquals(len(first), len(second))
+ for i in xrange(len(first)):
+ if isinstance(first[i], object):
+ self.assertObjEquals(first[i], second[i])
+ else:
+ self.assertEquals(first[i], second[i])
+
+ def assertTextEquals(self, golden_text, generated_text):
+ stripped_golden = [l.strip() for l in golden_text.split('\n')]
+ stripped_generated = [l.strip() for l in generated_text.split('\n')]
+ if stripped_golden != stripped_generated:
+ print self.id()
+ for line in difflib.context_diff(stripped_golden, stripped_generated):
+ print line
+ print '\n\nGenerated'
+ print '=' * 80
+ print generated_text
+ print '=' * 80
+ self.fail('Golden text mismatch')
+
+ def testNatives(self):
+ test_data = """"
+ interface OnFrameAvailableListener {}
+ private native int nativeInit();
+ private native void nativeDestroy(int nativeChromeBrowserProvider);
+ private native long nativeAddBookmark(
+ int nativeChromeBrowserProvider,
+ String url, String title, boolean isFolder, long parentId);
+ private static native String nativeGetDomainAndRegistry(String url);
+ private static native void nativeCreateHistoricalTabFromState(
+ byte[] state, int tab_index);
+ private native byte[] nativeGetStateAsByteArray(View view);
+ private static native String[] nativeGetAutofillProfileGUIDs();
+ private native void nativeSetRecognitionResults(
+ int sessionId, String[] results);
+ private native long nativeAddBookmarkFromAPI(
+ int nativeChromeBrowserProvider,
+ String url, Long created, Boolean isBookmark,
+ Long date, byte[] favicon, String title, Integer visits);
+ native int nativeFindAll(String find);
+ private static native OnFrameAvailableListener nativeGetInnerClass();
+ private native Bitmap nativeQueryBitmap(
+ int nativeChromeBrowserProvider,
+ String[] projection, String selection,
+ String[] selectionArgs, String sortOrder);
+ private native void nativeGotOrientation(
+ int nativeDataFetcherImplAndroid,
+ double alpha, double beta, double gamma);
+ """
+ jni_generator.JniParams.ExtractImportsAndInnerClasses(test_data)
+ natives = jni_generator.ExtractNatives(test_data)
+ golden_natives = [
+ NativeMethod(return_type='int', static=False,
+ name='Init',
+ params=[],
+ java_class_name=None,
+ type='function'),
+ NativeMethod(return_type='void', static=False, name='Destroy',
+ params=[Param(datatype='int',
+ name='nativeChromeBrowserProvider')],
+ java_class_name=None,
+ type='method',
+ p0_type='ChromeBrowserProvider'),
+ NativeMethod(return_type='long', static=False, name='AddBookmark',
+ params=[Param(datatype='int',
+ name='nativeChromeBrowserProvider'),
+ Param(datatype='String',
+ name='url'),
+ Param(datatype='String',
+ name='title'),
+ Param(datatype='boolean',
+ name='isFolder'),
+ Param(datatype='long',
+ name='parentId')],
+ java_class_name=None,
+ type='method',
+ p0_type='ChromeBrowserProvider'),
+ NativeMethod(return_type='String', static=True,
+ name='GetDomainAndRegistry',
+ params=[Param(datatype='String',
+ name='url')],
+ java_class_name=None,
+ type='function'),
+ NativeMethod(return_type='void', static=True,
+ name='CreateHistoricalTabFromState',
+ params=[Param(datatype='byte[]',
+ name='state'),
+ Param(datatype='int',
+ name='tab_index')],
+ java_class_name=None,
+ type='function'),
+ NativeMethod(return_type='byte[]', static=False,
+ name='GetStateAsByteArray',
+ params=[Param(datatype='View', name='view')],
+ java_class_name=None,
+ type='function'),
+ NativeMethod(return_type='String[]', static=True,
+ name='GetAutofillProfileGUIDs', params=[],
+ java_class_name=None,
+ type='function'),
+ NativeMethod(return_type='void', static=False,
+ name='SetRecognitionResults',
+ params=[Param(datatype='int', name='sessionId'),
+ Param(datatype='String[]', name='results')],
+ java_class_name=None,
+ type='function'),
+ NativeMethod(return_type='long', static=False,
+ name='AddBookmarkFromAPI',
+ params=[Param(datatype='int',
+ name='nativeChromeBrowserProvider'),
+ Param(datatype='String',
+ name='url'),
+ Param(datatype='Long',
+ name='created'),
+ Param(datatype='Boolean',
+ name='isBookmark'),
+ Param(datatype='Long',
+ name='date'),
+ Param(datatype='byte[]',
+ name='favicon'),
+ Param(datatype='String',
+ name='title'),
+ Param(datatype='Integer',
+ name='visits')],
+ java_class_name=None,
+ type='method',
+ p0_type='ChromeBrowserProvider'),
+ NativeMethod(return_type='int', static=False,
+ name='FindAll',
+ params=[Param(datatype='String',
+ name='find')],
+ java_class_name=None,
+ type='function'),
+ NativeMethod(return_type='OnFrameAvailableListener', static=True,
+ name='GetInnerClass',
+ params=[],
+ java_class_name=None,
+ type='function'),
+ NativeMethod(return_type='Bitmap',
+ static=False,
+ name='QueryBitmap',
+ params=[Param(datatype='int',
+ name='nativeChromeBrowserProvider'),
+ Param(datatype='String[]',
+ name='projection'),
+ Param(datatype='String',
+ name='selection'),
+ Param(datatype='String[]',
+ name='selectionArgs'),
+ Param(datatype='String',
+ name='sortOrder'),
+ ],
+ java_class_name=None,
+ type='method',
+ p0_type='ChromeBrowserProvider'),
+ NativeMethod(return_type='void', static=False,
+ name='GotOrientation',
+ params=[Param(datatype='int',
+ name='nativeDataFetcherImplAndroid'),
+ Param(datatype='double',
+ name='alpha'),
+ Param(datatype='double',
+ name='beta'),
+ Param(datatype='double',
+ name='gamma'),
+ ],
+ java_class_name=None,
+ type='method',
+ p0_type='content::DataFetcherImplAndroid'),
+ ]
+ self.assertListEquals(golden_natives, natives)
+ h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
+ natives, [])
+ golden_content = """\
+// Copyright (c) 2012 The Chromium Authors. 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 autogenerated by
+// base/android/jni_generator/jni_generator_tests.py
+// For
+// org/chromium/TestJni
+
+#ifndef org_chromium_TestJni_JNI
+#define org_chromium_TestJni_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+using base::android::ScopedJavaLocalRef;
+
+// Step 1: forward declarations.
+namespace {
+const char kTestJniClassPath[] = "org/chromium/TestJni";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_TestJni_clazz = NULL;
+} // namespace
+
+static jint Init(JNIEnv* env, jobject obj);
+
+static jstring GetDomainAndRegistry(JNIEnv* env, jclass clazz,
+ jstring url);
+
+static void CreateHistoricalTabFromState(JNIEnv* env, jclass clazz,
+ jbyteArray state,
+ jint tab_index);
+
+static jbyteArray GetStateAsByteArray(JNIEnv* env, jobject obj,
+ jobject view);
+
+static jobjectArray GetAutofillProfileGUIDs(JNIEnv* env, jclass clazz);
+
+static void SetRecognitionResults(JNIEnv* env, jobject obj,
+ jint sessionId,
+ jobjectArray results);
+
+static jint FindAll(JNIEnv* env, jobject obj,
+ jstring find);
+
+static jobject GetInnerClass(JNIEnv* env, jclass clazz);
+
+// Step 2: method stubs.
+static void Destroy(JNIEnv* env, jobject obj,
+ jint nativeChromeBrowserProvider) {
+ DCHECK(nativeChromeBrowserProvider) << "Destroy";
+ ChromeBrowserProvider* native =
+ reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
+ return native->Destroy(env, obj);
+}
+
+static jlong AddBookmark(JNIEnv* env, jobject obj,
+ jint nativeChromeBrowserProvider,
+ jstring url,
+ jstring title,
+ jboolean isFolder,
+ jlong parentId) {
+ DCHECK(nativeChromeBrowserProvider) << "AddBookmark";
+ ChromeBrowserProvider* native =
+ reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
+ return native->AddBookmark(env, obj, url, title, isFolder, parentId);
+}
+
+static jlong AddBookmarkFromAPI(JNIEnv* env, jobject obj,
+ jint nativeChromeBrowserProvider,
+ jstring url,
+ jobject created,
+ jobject isBookmark,
+ jobject date,
+ jbyteArray favicon,
+ jstring title,
+ jobject visits) {
+ DCHECK(nativeChromeBrowserProvider) << "AddBookmarkFromAPI";
+ ChromeBrowserProvider* native =
+ reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
+ return native->AddBookmarkFromAPI(env, obj, url, created, isBookmark, date,
+ favicon, title, visits);
+}
+
+static jobject QueryBitmap(JNIEnv* env, jobject obj,
+ jint nativeChromeBrowserProvider,
+ jobjectArray projection,
+ jstring selection,
+ jobjectArray selectionArgs,
+ jstring sortOrder) {
+ DCHECK(nativeChromeBrowserProvider) << "QueryBitmap";
+ ChromeBrowserProvider* native =
+ reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
+ return native->QueryBitmap(env, obj, projection, selection, selectionArgs,
+ sortOrder).Release();
+}
+
+static void GotOrientation(JNIEnv* env, jobject obj,
+ jint nativeDataFetcherImplAndroid,
+ jdouble alpha,
+ jdouble beta,
+ jdouble gamma) {
+ DCHECK(nativeDataFetcherImplAndroid) << "GotOrientation";
+ DataFetcherImplAndroid* native =
+ reinterpret_cast<DataFetcherImplAndroid*>(nativeDataFetcherImplAndroid);
+ return native->GotOrientation(env, obj, alpha, beta, gamma);
+}
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+ g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+ base::android::GetUnscopedClass(env, kTestJniClassPath)));
+ static const JNINativeMethod kMethodsTestJni[] = {
+ { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+ { "nativeDestroy",
+"("
+"I"
+")"
+"V", reinterpret_cast<void*>(Destroy) },
+ { "nativeAddBookmark",
+"("
+"I"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+"Z"
+"J"
+")"
+"J", reinterpret_cast<void*>(AddBookmark) },
+ { "nativeGetDomainAndRegistry",
+"("
+"Ljava/lang/String;"
+")"
+"Ljava/lang/String;", reinterpret_cast<void*>(GetDomainAndRegistry) },
+ { "nativeCreateHistoricalTabFromState",
+"("
+"[B"
+"I"
+")"
+"V", reinterpret_cast<void*>(CreateHistoricalTabFromState) },
+ { "nativeGetStateAsByteArray",
+"("
+"Landroid/view/View;"
+")"
+"[B", reinterpret_cast<void*>(GetStateAsByteArray) },
+ { "nativeGetAutofillProfileGUIDs",
+"("
+")"
+"[Ljava/lang/String;", reinterpret_cast<void*>(GetAutofillProfileGUIDs) },
+ { "nativeSetRecognitionResults",
+"("
+"I"
+"[Ljava/lang/String;"
+")"
+"V", reinterpret_cast<void*>(SetRecognitionResults) },
+ { "nativeAddBookmarkFromAPI",
+"("
+"I"
+"Ljava/lang/String;"
+"Ljava/lang/Long;"
+"Ljava/lang/Boolean;"
+"Ljava/lang/Long;"
+"[B"
+"Ljava/lang/String;"
+"Ljava/lang/Integer;"
+")"
+"J", reinterpret_cast<void*>(AddBookmarkFromAPI) },
+ { "nativeFindAll",
+"("
+"Ljava/lang/String;"
+")"
+"I", reinterpret_cast<void*>(FindAll) },
+ { "nativeGetInnerClass",
+"("
+")"
+"Lorg/chromium/example/jni_generator/SampleForTests$OnFrameAvailableListener;",
+ reinterpret_cast<void*>(GetInnerClass) },
+ { "nativeQueryBitmap",
+"("
+"I"
+"[Ljava/lang/String;"
+"Ljava/lang/String;"
+"[Ljava/lang/String;"
+"Ljava/lang/String;"
+")"
+"Landroid/graphics/Bitmap;", reinterpret_cast<void*>(QueryBitmap) },
+ { "nativeGotOrientation",
+"("
+"I"
+"D"
+"D"
+"D"
+")"
+"V", reinterpret_cast<void*>(GotOrientation) },
+ };
+ const int kMethodsTestJniSize = arraysize(kMethodsTestJni);
+
+ if (env->RegisterNatives(g_TestJni_clazz,
+ kMethodsTestJni,
+ kMethodsTestJniSize) < 0) {
+ LOG(ERROR) << "RegisterNatives failed in " << __FILE__;
+ return false;
+ }
+
+ return true;
+}
+
+#endif // org_chromium_TestJni_JNI
+"""
+ self.assertTextEquals(golden_content, h.GetContent())
+
+ def testInnerClassNatives(self):
+ test_data = """
+ class MyInnerClass {
+ @NativeCall("MyInnerClass")
+ private native int nativeInit();
+ }
+ """
+ natives = jni_generator.ExtractNatives(test_data)
+ golden_natives = [
+ NativeMethod(return_type='int', static=False,
+ name='Init', params=[],
+ java_class_name='MyInnerClass',
+ type='function')
+ ]
+ self.assertListEquals(golden_natives, natives)
+ h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
+ natives, [])
+ golden_content = """\
+// Copyright (c) 2012 The Chromium Authors. 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 autogenerated by
+// base/android/jni_generator/jni_generator_tests.py
+// For
+// org/chromium/TestJni
+
+#ifndef org_chromium_TestJni_JNI
+#define org_chromium_TestJni_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+using base::android::ScopedJavaLocalRef;
+
+// Step 1: forward declarations.
+namespace {
+const char kTestJniClassPath[] = "org/chromium/TestJni";
+const char kMyInnerClassClassPath[] = "org/chromium/TestJni$MyInnerClass";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_TestJni_clazz = NULL;
+} // namespace
+
+static jint Init(JNIEnv* env, jobject obj);
+
+// Step 2: method stubs.
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+ g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+ base::android::GetUnscopedClass(env, kTestJniClassPath)));
+ static const JNINativeMethod kMethodsMyInnerClass[] = {
+ { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+ };
+ const int kMethodsMyInnerClassSize = arraysize(kMethodsMyInnerClass);
+
+ if (env->RegisterNatives(g_MyInnerClass_clazz,
+ kMethodsMyInnerClass,
+ kMethodsMyInnerClassSize) < 0) {
+ LOG(ERROR) << "RegisterNatives failed in " << __FILE__;
+ return false;
+ }
+
+ return true;
+}
+
+#endif // org_chromium_TestJni_JNI
+"""
+ self.assertTextEquals(golden_content, h.GetContent())
+
+ def testInnerClassNativesMultiple(self):
+ test_data = """
+ class MyInnerClass {
+ @NativeCall("MyInnerClass")
+ private native int nativeInit();
+ }
+ class MyOtherInnerClass {
+ @NativeCall("MyOtherInnerClass")
+ private native int nativeInit();
+ }
+ """
+ natives = jni_generator.ExtractNatives(test_data)
+ golden_natives = [
+ NativeMethod(return_type='int', static=False,
+ name='Init', params=[],
+ java_class_name='MyInnerClass',
+ type='function'),
+ NativeMethod(return_type='int', static=False,
+ name='Init', params=[],
+ java_class_name='MyOtherInnerClass',
+ type='function')
+ ]
+ self.assertListEquals(golden_natives, natives)
+ h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
+ natives, [])
+ golden_content = """\
+// Copyright (c) 2012 The Chromium Authors. 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 autogenerated by
+// base/android/jni_generator/jni_generator_tests.py
+// For
+// org/chromium/TestJni
+
+#ifndef org_chromium_TestJni_JNI
+#define org_chromium_TestJni_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+using base::android::ScopedJavaLocalRef;
+
+// Step 1: forward declarations.
+namespace {
+const char kMyOtherInnerClassClassPath[] =
+ "org/chromium/TestJni$MyOtherInnerClass";
+const char kTestJniClassPath[] = "org/chromium/TestJni";
+const char kMyInnerClassClassPath[] = "org/chromium/TestJni$MyInnerClass";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_TestJni_clazz = NULL;
+} // namespace
+
+static jint Init(JNIEnv* env, jobject obj);
+
+static jint Init(JNIEnv* env, jobject obj);
+
+// Step 2: method stubs.
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+ g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+ base::android::GetUnscopedClass(env, kTestJniClassPath)));
+ static const JNINativeMethod kMethodsMyOtherInnerClass[] = {
+ { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+ };
+ const int kMethodsMyOtherInnerClassSize =
+ arraysize(kMethodsMyOtherInnerClass);
+
+ if (env->RegisterNatives(g_MyOtherInnerClass_clazz,
+ kMethodsMyOtherInnerClass,
+ kMethodsMyOtherInnerClassSize) < 0) {
+ LOG(ERROR) << "RegisterNatives failed in " << __FILE__;
+ return false;
+ }
+
+ static const JNINativeMethod kMethodsMyInnerClass[] = {
+ { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+ };
+ const int kMethodsMyInnerClassSize = arraysize(kMethodsMyInnerClass);
+
+ if (env->RegisterNatives(g_MyInnerClass_clazz,
+ kMethodsMyInnerClass,
+ kMethodsMyInnerClassSize) < 0) {
+ LOG(ERROR) << "RegisterNatives failed in " << __FILE__;
+ return false;
+ }
+
+ return true;
+}
+
+#endif // org_chromium_TestJni_JNI
+"""
+ self.assertTextEquals(golden_content, h.GetContent())
+
+ def testInnerClassNativesBothInnerAndOuter(self):
+ test_data = """
+ class MyOuterClass {
+ private native int nativeInit();
+ class MyOtherInnerClass {
+ @NativeCall("MyOtherInnerClass")
+ private native int nativeInit();
+ }
+ }
+ """
+ natives = jni_generator.ExtractNatives(test_data)
+ golden_natives = [
+ NativeMethod(return_type='int', static=False,
+ name='Init', params=[],
+ java_class_name=None,
+ type='function'),
+ NativeMethod(return_type='int', static=False,
+ name='Init', params=[],
+ java_class_name='MyOtherInnerClass',
+ type='function')
+ ]
+ self.assertListEquals(golden_natives, natives)
+ h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
+ natives, [])
+ golden_content = """\
+// Copyright (c) 2012 The Chromium Authors. 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 autogenerated by
+// base/android/jni_generator/jni_generator_tests.py
+// For
+// org/chromium/TestJni
+
+#ifndef org_chromium_TestJni_JNI
+#define org_chromium_TestJni_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+using base::android::ScopedJavaLocalRef;
+
+// Step 1: forward declarations.
+namespace {
+const char kMyOtherInnerClassClassPath[] =
+ "org/chromium/TestJni$MyOtherInnerClass";
+const char kTestJniClassPath[] = "org/chromium/TestJni";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_TestJni_clazz = NULL;
+} // namespace
+
+static jint Init(JNIEnv* env, jobject obj);
+
+static jint Init(JNIEnv* env, jobject obj);
+
+// Step 2: method stubs.
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+ g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+ base::android::GetUnscopedClass(env, kTestJniClassPath)));
+ static const JNINativeMethod kMethodsMyOtherInnerClass[] = {
+ { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+ };
+ const int kMethodsMyOtherInnerClassSize =
+ arraysize(kMethodsMyOtherInnerClass);
+
+ if (env->RegisterNatives(g_MyOtherInnerClass_clazz,
+ kMethodsMyOtherInnerClass,
+ kMethodsMyOtherInnerClassSize) < 0) {
+ LOG(ERROR) << "RegisterNatives failed in " << __FILE__;
+ return false;
+ }
+
+ static const JNINativeMethod kMethodsTestJni[] = {
+ { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+ };
+ const int kMethodsTestJniSize = arraysize(kMethodsTestJni);
+
+ if (env->RegisterNatives(g_TestJni_clazz,
+ kMethodsTestJni,
+ kMethodsTestJniSize) < 0) {
+ LOG(ERROR) << "RegisterNatives failed in " << __FILE__;
+ return false;
+ }
+
+ return true;
+}
+
+#endif // org_chromium_TestJni_JNI
+"""
+ self.assertTextEquals(golden_content, h.GetContent())
+
+ def testCalledByNatives(self):
+ test_data = """"
+ import android.graphics.Bitmap;
+ import android.view.View;
+ import java.io.InputStream;
+
+ class InnerClass {}
+
+ @CalledByNative
+ InnerClass showConfirmInfoBar(int nativeInfoBar,
+ String buttonOk, String buttonCancel, String title, Bitmap icon) {
+ InfoBar infobar = new ConfirmInfoBar(nativeInfoBar, mContext,
+ buttonOk, buttonCancel,
+ title, icon);
+ return infobar;
+ }
+ @CalledByNative
+ InnerClass showAutoLoginInfoBar(int nativeInfoBar,
+ String realm, String account, String args) {
+ AutoLoginInfoBar infobar = new AutoLoginInfoBar(nativeInfoBar, mContext,
+ realm, account, args);
+ if (infobar.displayedAccountCount() == 0)
+ infobar = null;
+ return infobar;
+ }
+ @CalledByNative("InfoBar")
+ void dismiss();
+ @SuppressWarnings("unused")
+ @CalledByNative
+ private static boolean shouldShowAutoLogin(View view,
+ String realm, String account, String args) {
+ AccountManagerContainer accountManagerContainer =
+ new AccountManagerContainer((Activity)contentView.getContext(),
+ realm, account, args);
+ String[] logins = accountManagerContainer.getAccountLogins(null);
+ return logins.length != 0;
+ }
+ @CalledByNative
+ static InputStream openUrl(String url) {
+ return null;
+ }
+ @CalledByNative
+ private void activateHardwareAcceleration(final boolean activated,
+ final int iPid, final int iType,
+ final int iPrimaryID, final int iSecondaryID) {
+ if (!activated) {
+ return
+ }
+ }
+ @CalledByNativeUnchecked
+ private void uncheckedCall(int iParam);
+ """
+ jni_generator.JniParams.SetFullyQualifiedClass('org/chromium/Foo')
+ jni_generator.JniParams.ExtractImportsAndInnerClasses(test_data)
+ called_by_natives = jni_generator.ExtractCalledByNatives(test_data)
+ golden_called_by_natives = [
+ CalledByNative(
+ return_type='InnerClass',
+ system_class=False,
+ static=False,
+ name='showConfirmInfoBar',
+ method_id_var_name='showConfirmInfoBar',
+ java_class_name='',
+ params=[Param(datatype='int', name='nativeInfoBar'),
+ Param(datatype='String', name='buttonOk'),
+ Param(datatype='String', name='buttonCancel'),
+ Param(datatype='String', name='title'),
+ Param(datatype='Bitmap', name='icon')],
+ env_call=('Object', ''),
+ unchecked=False,
+ ),
+ CalledByNative(
+ return_type='InnerClass',
+ system_class=False,
+ static=False,
+ name='showAutoLoginInfoBar',
+ method_id_var_name='showAutoLoginInfoBar',
+ java_class_name='',
+ params=[Param(datatype='int', name='nativeInfoBar'),
+ Param(datatype='String', name='realm'),
+ Param(datatype='String', name='account'),
+ Param(datatype='String', name='args')],
+ env_call=('Object', ''),
+ unchecked=False,
+ ),
+ CalledByNative(
+ return_type='void',
+ system_class=False,
+ static=False,
+ name='dismiss',
+ method_id_var_name='dismiss',
+ java_class_name='InfoBar',
+ params=[],
+ env_call=('Void', ''),
+ unchecked=False,
+ ),
+ CalledByNative(
+ return_type='boolean',
+ system_class=False,
+ static=True,
+ name='shouldShowAutoLogin',
+ method_id_var_name='shouldShowAutoLogin',
+ java_class_name='',
+ params=[Param(datatype='View', name='view'),
+ Param(datatype='String', name='realm'),
+ Param(datatype='String', name='account'),
+ Param(datatype='String', name='args')],
+ env_call=('Boolean', ''),
+ unchecked=False,
+ ),
+ CalledByNative(
+ return_type='InputStream',
+ system_class=False,
+ static=True,
+ name='openUrl',
+ method_id_var_name='openUrl',
+ java_class_name='',
+ params=[Param(datatype='String', name='url')],
+ env_call=('Object', ''),
+ unchecked=False,
+ ),
+ CalledByNative(
+ return_type='void',
+ system_class=False,
+ static=False,
+ name='activateHardwareAcceleration',
+ method_id_var_name='activateHardwareAcceleration',
+ java_class_name='',
+ params=[Param(datatype='boolean', name='activated'),
+ Param(datatype='int', name='iPid'),
+ Param(datatype='int', name='iType'),
+ Param(datatype='int', name='iPrimaryID'),
+ Param(datatype='int', name='iSecondaryID'),
+ ],
+ env_call=('Void', ''),
+ unchecked=False,
+ ),
+ CalledByNative(
+ return_type='void',
+ system_class=False,
+ static=False,
+ name='uncheckedCall',
+ method_id_var_name='uncheckedCall',
+ java_class_name='',
+ params=[Param(datatype='int', name='iParam')],
+ env_call=('Void', ''),
+ unchecked=True,
+ ),
+ ]
+ self.assertListEquals(golden_called_by_natives, called_by_natives)
+ h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
+ [], called_by_natives)
+ golden_content = """\
+// Copyright (c) 2012 The Chromium Authors. 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 autogenerated by
+// base/android/jni_generator/jni_generator_tests.py
+// For
+// org/chromium/TestJni
+
+#ifndef org_chromium_TestJni_JNI
+#define org_chromium_TestJni_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+using base::android::ScopedJavaLocalRef;
+
+// Step 1: forward declarations.
+namespace {
+const char kTestJniClassPath[] = "org/chromium/TestJni";
+const char kInfoBarClassPath[] = "org/chromium/TestJni$InfoBar";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_TestJni_clazz = NULL;
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_InfoBar_clazz = NULL;
+} // namespace
+
+// Step 2: method stubs.
+
+static base::subtle::AtomicWord g_TestJni_showConfirmInfoBar = 0;
+static ScopedJavaLocalRef<jobject> Java_TestJni_showConfirmInfoBar(JNIEnv* env,
+ jobject obj, jint nativeInfoBar,
+ jstring buttonOk,
+ jstring buttonCancel,
+ jstring title,
+ jobject icon) {
+ /* Must call RegisterNativesImpl() */
+ DCHECK(g_TestJni_clazz);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_INSTANCE>(
+ env, g_TestJni_clazz,
+ "showConfirmInfoBar",
+
+"("
+"I"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+"Landroid/graphics/Bitmap;"
+")"
+"Lorg/chromium/Foo$InnerClass;",
+ &g_TestJni_showConfirmInfoBar);
+
+ jobject ret =
+ env->CallObjectMethod(obj,
+ method_id, nativeInfoBar, buttonOk, buttonCancel, title, icon);
+ base::android::CheckException(env);
+ return ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_showAutoLoginInfoBar = 0;
+static ScopedJavaLocalRef<jobject> Java_TestJni_showAutoLoginInfoBar(JNIEnv*
+ env, jobject obj, jint nativeInfoBar,
+ jstring realm,
+ jstring account,
+ jstring args) {
+ /* Must call RegisterNativesImpl() */
+ DCHECK(g_TestJni_clazz);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_INSTANCE>(
+ env, g_TestJni_clazz,
+ "showAutoLoginInfoBar",
+
+"("
+"I"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+")"
+"Lorg/chromium/Foo$InnerClass;",
+ &g_TestJni_showAutoLoginInfoBar);
+
+ jobject ret =
+ env->CallObjectMethod(obj,
+ method_id, nativeInfoBar, realm, account, args);
+ base::android::CheckException(env);
+ return ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_InfoBar_dismiss = 0;
+static void Java_InfoBar_dismiss(JNIEnv* env, jobject obj) {
+ /* Must call RegisterNativesImpl() */
+ DCHECK(g_InfoBar_clazz);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_INSTANCE>(
+ env, g_InfoBar_clazz,
+ "dismiss",
+
+"("
+")"
+"V",
+ &g_InfoBar_dismiss);
+
+ env->CallVoidMethod(obj,
+ method_id);
+ base::android::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_TestJni_shouldShowAutoLogin = 0;
+static jboolean Java_TestJni_shouldShowAutoLogin(JNIEnv* env, jobject view,
+ jstring realm,
+ jstring account,
+ jstring args) {
+ /* Must call RegisterNativesImpl() */
+ DCHECK(g_TestJni_clazz);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_STATIC>(
+ env, g_TestJni_clazz,
+ "shouldShowAutoLogin",
+
+"("
+"Landroid/view/View;"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+")"
+"Z",
+ &g_TestJni_shouldShowAutoLogin);
+
+ jboolean ret =
+ env->CallStaticBooleanMethod(g_TestJni_clazz,
+ method_id, view, realm, account, args);
+ base::android::CheckException(env);
+ return ret;
+}
+
+static base::subtle::AtomicWord g_TestJni_openUrl = 0;
+static ScopedJavaLocalRef<jobject> Java_TestJni_openUrl(JNIEnv* env, jstring
+ url) {
+ /* Must call RegisterNativesImpl() */
+ DCHECK(g_TestJni_clazz);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_STATIC>(
+ env, g_TestJni_clazz,
+ "openUrl",
+
+"("
+"Ljava/lang/String;"
+")"
+"Ljava/io/InputStream;",
+ &g_TestJni_openUrl);
+
+ jobject ret =
+ env->CallStaticObjectMethod(g_TestJni_clazz,
+ method_id, url);
+ base::android::CheckException(env);
+ return ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_activateHardwareAcceleration = 0;
+static void Java_TestJni_activateHardwareAcceleration(JNIEnv* env, jobject obj,
+ jboolean activated,
+ jint iPid,
+ jint iType,
+ jint iPrimaryID,
+ jint iSecondaryID) {
+ /* Must call RegisterNativesImpl() */
+ DCHECK(g_TestJni_clazz);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_INSTANCE>(
+ env, g_TestJni_clazz,
+ "activateHardwareAcceleration",
+
+"("
+"Z"
+"I"
+"I"
+"I"
+"I"
+")"
+"V",
+ &g_TestJni_activateHardwareAcceleration);
+
+ env->CallVoidMethod(obj,
+ method_id, activated, iPid, iType, iPrimaryID, iSecondaryID);
+ base::android::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_TestJni_uncheckedCall = 0;
+static void Java_TestJni_uncheckedCall(JNIEnv* env, jobject obj, jint iParam) {
+ /* Must call RegisterNativesImpl() */
+ DCHECK(g_TestJni_clazz);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_INSTANCE>(
+ env, g_TestJni_clazz,
+ "uncheckedCall",
+
+"("
+"I"
+")"
+"V",
+ &g_TestJni_uncheckedCall);
+
+ env->CallVoidMethod(obj,
+ method_id, iParam);
+
+}
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+ g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+ base::android::GetUnscopedClass(env, kTestJniClassPath)));
+ g_InfoBar_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+ base::android::GetUnscopedClass(env, kInfoBarClassPath)));
+ return true;
+}
+
+#endif // org_chromium_TestJni_JNI
+"""
+ self.assertTextEquals(golden_content, h.GetContent())
+
+ def testCalledByNativeParseError(self):
+ try:
+ jni_generator.ExtractCalledByNatives("""
+@CalledByNative
+public static int foo(); // This one is fine
+
+@CalledByNative
+scooby doo
+""")
+ self.fail('Expected a ParseError')
+ except jni_generator.ParseError, e:
+ self.assertEquals(('@CalledByNative', 'scooby doo'), e.context_lines)
+
+ def testFullyQualifiedClassName(self):
+ contents = """
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.content.browser;
+
+import org.chromium.base.BuildInfo;
+"""
+ self.assertEquals('org/chromium/content/browser/Foo',
+ jni_generator.ExtractFullyQualifiedJavaClassName(
+ 'org/chromium/content/browser/Foo.java', contents))
+ self.assertEquals('org/chromium/content/browser/Foo',
+ jni_generator.ExtractFullyQualifiedJavaClassName(
+ 'frameworks/Foo.java', contents))
+ self.assertRaises(SyntaxError,
+ jni_generator.ExtractFullyQualifiedJavaClassName,
+ 'com/foo/Bar', 'no PACKAGE line')
+
+ def testMethodNameMangling(self):
+ self.assertEquals('closeV',
+ jni_generator.GetMangledMethodName('close', [], 'void'))
+ self.assertEquals('readI_AB_I_I',
+ jni_generator.GetMangledMethodName('read',
+ [Param(name='p1',
+ datatype='byte[]'),
+ Param(name='p2',
+ datatype='int'),
+ Param(name='p3',
+ datatype='int'),],
+ 'int'))
+ self.assertEquals('openJIIS_JLS',
+ jni_generator.GetMangledMethodName('open',
+ [Param(name='p1',
+ datatype='java/lang/String'),],
+ 'java/io/InputStream'))
+
+ def testFromJavaP(self):
+ contents = """
+public abstract class java.io.InputStream extends java.lang.Object
+ implements java.io.Closeable{
+ public java.io.InputStream();
+ public int available() throws java.io.IOException;
+ public void close() throws java.io.IOException;
+ public void mark(int);
+ public boolean markSupported();
+ public abstract int read() throws java.io.IOException;
+ public int read(byte[]) throws java.io.IOException;
+ public int read(byte[], int, int) throws java.io.IOException;
+ public synchronized void reset() throws java.io.IOException;
+ public long skip(long) throws java.io.IOException;
+}
+"""
+ jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'), None)
+ self.assertEquals(10, len(jni_from_javap.called_by_natives))
+ golden_content = """\
+// Copyright (c) 2012 The Chromium Authors. 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 autogenerated by
+// base/android/jni_generator/jni_generator_tests.py
+// For
+// java/io/InputStream
+
+#ifndef java_io_InputStream_JNI
+#define java_io_InputStream_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+using base::android::ScopedJavaLocalRef;
+
+// Step 1: forward declarations.
+namespace {
+const char kInputStreamClassPath[] = "java/io/InputStream";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_InputStream_clazz = NULL;
+} // namespace
+
+namespace JNI_InputStream {
+
+// Step 2: method stubs.
+
+static base::subtle::AtomicWord g_InputStream_available = 0;
+static jint Java_InputStream_available(JNIEnv* env, jobject obj) __attribute__
+ ((unused));
+static jint Java_InputStream_available(JNIEnv* env, jobject obj) {
+ /* Must call RegisterNativesImpl() */
+ DCHECK(g_InputStream_clazz);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_INSTANCE>(
+ env, g_InputStream_clazz,
+ "available",
+
+"("
+")"
+"I",
+ &g_InputStream_available);
+
+ jint ret =
+ env->CallIntMethod(obj,
+ method_id);
+ base::android::CheckException(env);
+ return ret;
+}
+
+static base::subtle::AtomicWord g_InputStream_close = 0;
+static void Java_InputStream_close(JNIEnv* env, jobject obj) __attribute__
+ ((unused));
+static void Java_InputStream_close(JNIEnv* env, jobject obj) {
+ /* Must call RegisterNativesImpl() */
+ DCHECK(g_InputStream_clazz);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_INSTANCE>(
+ env, g_InputStream_clazz,
+ "close",
+
+"("
+")"
+"V",
+ &g_InputStream_close);
+
+ env->CallVoidMethod(obj,
+ method_id);
+ base::android::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_InputStream_mark = 0;
+static void Java_InputStream_mark(JNIEnv* env, jobject obj, jint p0)
+ __attribute__ ((unused));
+static void Java_InputStream_mark(JNIEnv* env, jobject obj, jint p0) {
+ /* Must call RegisterNativesImpl() */
+ DCHECK(g_InputStream_clazz);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_INSTANCE>(
+ env, g_InputStream_clazz,
+ "mark",
+
+"("
+"I"
+")"
+"V",
+ &g_InputStream_mark);
+
+ env->CallVoidMethod(obj,
+ method_id, p0);
+ base::android::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_InputStream_markSupported = 0;
+static jboolean Java_InputStream_markSupported(JNIEnv* env, jobject obj)
+ __attribute__ ((unused));
+static jboolean Java_InputStream_markSupported(JNIEnv* env, jobject obj) {
+ /* Must call RegisterNativesImpl() */
+ DCHECK(g_InputStream_clazz);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_INSTANCE>(
+ env, g_InputStream_clazz,
+ "markSupported",
+
+"("
+")"
+"Z",
+ &g_InputStream_markSupported);
+
+ jboolean ret =
+ env->CallBooleanMethod(obj,
+ method_id);
+ base::android::CheckException(env);
+ return ret;
+}
+
+static base::subtle::AtomicWord g_InputStream_readI = 0;
+static jint Java_InputStream_readI(JNIEnv* env, jobject obj) __attribute__
+ ((unused));
+static jint Java_InputStream_readI(JNIEnv* env, jobject obj) {
+ /* Must call RegisterNativesImpl() */
+ DCHECK(g_InputStream_clazz);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_INSTANCE>(
+ env, g_InputStream_clazz,
+ "read",
+
+"("
+")"
+"I",
+ &g_InputStream_readI);
+
+ jint ret =
+ env->CallIntMethod(obj,
+ method_id);
+ base::android::CheckException(env);
+ return ret;
+}
+
+static base::subtle::AtomicWord g_InputStream_readI_AB = 0;
+static jint Java_InputStream_readI_AB(JNIEnv* env, jobject obj, jbyteArray p0)
+ __attribute__ ((unused));
+static jint Java_InputStream_readI_AB(JNIEnv* env, jobject obj, jbyteArray p0) {
+ /* Must call RegisterNativesImpl() */
+ DCHECK(g_InputStream_clazz);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_INSTANCE>(
+ env, g_InputStream_clazz,
+ "read",
+
+"("
+"[B"
+")"
+"I",
+ &g_InputStream_readI_AB);
+
+ jint ret =
+ env->CallIntMethod(obj,
+ method_id, p0);
+ base::android::CheckException(env);
+ return ret;
+}
+
+static base::subtle::AtomicWord g_InputStream_readI_AB_I_I = 0;
+static jint Java_InputStream_readI_AB_I_I(JNIEnv* env, jobject obj, jbyteArray
+ p0,
+ jint p1,
+ jint p2) __attribute__ ((unused));
+static jint Java_InputStream_readI_AB_I_I(JNIEnv* env, jobject obj, jbyteArray
+ p0,
+ jint p1,
+ jint p2) {
+ /* Must call RegisterNativesImpl() */
+ DCHECK(g_InputStream_clazz);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_INSTANCE>(
+ env, g_InputStream_clazz,
+ "read",
+
+"("
+"[B"
+"I"
+"I"
+")"
+"I",
+ &g_InputStream_readI_AB_I_I);
+
+ jint ret =
+ env->CallIntMethod(obj,
+ method_id, p0, p1, p2);
+ base::android::CheckException(env);
+ return ret;
+}
+
+static base::subtle::AtomicWord g_InputStream_reset = 0;
+static void Java_InputStream_reset(JNIEnv* env, jobject obj) __attribute__
+ ((unused));
+static void Java_InputStream_reset(JNIEnv* env, jobject obj) {
+ /* Must call RegisterNativesImpl() */
+ DCHECK(g_InputStream_clazz);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_INSTANCE>(
+ env, g_InputStream_clazz,
+ "reset",
+
+"("
+")"
+"V",
+ &g_InputStream_reset);
+
+ env->CallVoidMethod(obj,
+ method_id);
+ base::android::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_InputStream_skip = 0;
+static jlong Java_InputStream_skip(JNIEnv* env, jobject obj, jlong p0)
+ __attribute__ ((unused));
+static jlong Java_InputStream_skip(JNIEnv* env, jobject obj, jlong p0) {
+ /* Must call RegisterNativesImpl() */
+ DCHECK(g_InputStream_clazz);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_INSTANCE>(
+ env, g_InputStream_clazz,
+ "skip",
+
+"("
+"J"
+")"
+"J",
+ &g_InputStream_skip);
+
+ jlong ret =
+ env->CallLongMethod(obj,
+ method_id, p0);
+ base::android::CheckException(env);
+ return ret;
+}
+
+static base::subtle::AtomicWord g_InputStream_Constructor = 0;
+static ScopedJavaLocalRef<jobject> Java_InputStream_Constructor(JNIEnv* env)
+ __attribute__ ((unused));
+static ScopedJavaLocalRef<jobject> Java_InputStream_Constructor(JNIEnv* env) {
+ /* Must call RegisterNativesImpl() */
+ DCHECK(g_InputStream_clazz);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_INSTANCE>(
+ env, g_InputStream_clazz,
+ "<init>",
+
+"("
+")"
+"V",
+ &g_InputStream_Constructor);
+
+ jobject ret =
+ env->NewObject(g_InputStream_clazz,
+ method_id);
+ base::android::CheckException(env);
+ return ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+ g_InputStream_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+ base::android::GetUnscopedClass(env, kInputStreamClassPath)));
+ return true;
+}
+} // namespace JNI_InputStream
+
+#endif // java_io_InputStream_JNI
+"""
+ self.assertTextEquals(golden_content, jni_from_javap.GetContent())
+
+ def testREForNatives(self):
+ # We should not match "native SyncSetupFlow" inside the comment.
+ test_data = """
+ /**
+ * Invoked when the setup process is complete so we can disconnect from the
+ * native-side SyncSetupFlowHandler.
+ */
+ public void destroy() {
+ Log.v(TAG, "Destroying native SyncSetupFlow");
+ if (mNativeSyncSetupFlow != 0) {
+ nativeSyncSetupEnded(mNativeSyncSetupFlow);
+ mNativeSyncSetupFlow = 0;
+ }
+ }
+ private native void nativeSyncSetupEnded(
+ int nativeAndroidSyncSetupFlowHandler);
+ """
+ jni_from_java = jni_generator.JNIFromJavaSource(test_data, 'foo/bar')
+
+ def testRaisesOnNonJNIMethod(self):
+ test_data = """
+ class MyInnerClass {
+ private int Foo(int p0) {
+ }
+ }
+ """
+ self.assertRaises(SyntaxError,
+ jni_generator.JNIFromJavaSource,
+ test_data, 'foo/bar')
+
+ def testJniSelfDocumentingExample(self):
+ script_dir = os.path.dirname(sys.argv[0])
+ content = file(os.path.join(script_dir, 'SampleForTests.java')).read()
+ golden_content = file(os.path.join(script_dir,
+ 'golden_sample_for_tests_jni.h')).read()
+ jni_from_java = jni_generator.JNIFromJavaSource(
+ content, 'org/chromium/example/jni_generator/SampleForTests')
+ self.assertTextEquals(golden_content, jni_from_java.GetContent())
+
+ def testNoWrappingPreprocessorLines(self):
+ test_data = """
+ package com.google.lookhowextremelylongiam.snarf.icankeepthisupallday;
+
+ class ReallyLongClassNamesAreAllTheRage {
+ private static native int nativeTest();
+ }
+ """
+ jni_from_java = jni_generator.JNIFromJavaSource(
+ test_data, ('com/google/lookhowextremelylongiam/snarf/'
+ 'icankeepthisupallday/ReallyLongClassNamesAreAllTheRage'))
+ jni_lines = jni_from_java.GetContent().split('\n')
+ line = filter(lambda line: line.lstrip().startswith('#ifndef'),
+ jni_lines)[0]
+ self.assertTrue(len(line) > 80,
+ ('Expected #ifndef line to be > 80 chars: ', line))
+
+ def testImports(self):
+ import_header = """
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.content.app;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.SurfaceTexture;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.Surface;
+
+import java.util.ArrayList;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.base.JNINamespace;
+import org.chromium.content.app.ContentMain;
+import org.chromium.content.browser.SandboxedProcessConnection;
+import org.chromium.content.common.ISandboxedProcessCallback;
+import org.chromium.content.common.ISandboxedProcessService;
+import org.chromium.content.common.SurfaceCallback;
+import org.chromium.content.common.WillNotRaise.AnException;
+import org.chromium.content.common.WillRaise.AnException;
+
+import static org.chromium.Bar.Zoo;
+
+class Foo {
+ public static class BookmarkNode implements Parcelable {
+ }
+ public interface PasswordListObserver {
+ }
+}
+ """
+ jni_generator.JniParams.SetFullyQualifiedClass(
+ 'org/chromium/content/app/Foo')
+ jni_generator.JniParams.ExtractImportsAndInnerClasses(import_header)
+ self.assertTrue('Lorg/chromium/content/common/ISandboxedProcessService' in
+ jni_generator.JniParams._imports)
+ self.assertTrue('Lorg/chromium/Bar/Zoo' in
+ jni_generator.JniParams._imports)
+ self.assertTrue('Lorg/chromium/content/app/Foo$BookmarkNode' in
+ jni_generator.JniParams._inner_classes)
+ self.assertTrue('Lorg/chromium/content/app/Foo$PasswordListObserver' in
+ jni_generator.JniParams._inner_classes)
+ self.assertEquals('Lorg/chromium/content/app/ContentMain$Inner',
+ jni_generator.JniParams.JavaToJni('ContentMain.Inner'))
+ self.assertRaises(SyntaxError,
+ jni_generator.JniParams.JavaToJni,
+ 'AnException')
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/src/base/android/jni_generator/sample_for_tests.cc b/src/base/android/jni_generator/sample_for_tests.cc
new file mode 100644
index 0000000..5b5cfc5
--- /dev/null
+++ b/src/base/android/jni_generator/sample_for_tests.cc
@@ -0,0 +1,81 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+
+// The main purpose of this is to ensure sample_for_tests_jni.h
+// compiles and the functions declared in it as expected.
+
+using base::android::AttachCurrentThread;
+using base::android::ScopedJavaLocalRef;
+
+namespace base {
+namespace android {
+
+class CPPClass {
+ public:
+ class InnerClass {
+ public:
+ jdouble MethodOtherP0(JNIEnv* env, jobject obj) {
+ return 0.0;
+ }
+ };
+
+ void Destroy(JNIEnv* env, jobject obj) {
+ delete this;
+ }
+
+ jint Method(JNIEnv* env, jobject obj) {
+ return 0;
+ }
+
+ ScopedJavaLocalRef<jstring> InnerMethod(JNIEnv* env, jobject obj) {
+ return ScopedJavaLocalRef<jstring>();
+ }
+};
+
+static jint Init(JNIEnv* env, jobject obj) {
+ return 0;
+}
+
+static jdouble GetDoubleFunction(JNIEnv*, jobject) {
+ return 0;
+}
+
+static jfloat GetFloatFunction(JNIEnv*, jclass) {
+ return 0;
+}
+
+static void SetNonPODDatatype(JNIEnv*, jobject, jobject) {}
+
+static jobject GetNonPODDatatype(JNIEnv*, jobject) {
+ return NULL;
+}
+
+static jint InnerFunction(JNIEnv*, jclass) {
+ return 0;
+}
+
+} // namespace android
+} // namespace base
+
+#include "jni/SampleForTests_jni.h"
+
+int main() {
+ // On a regular application, you'd call AttachCurrentThread(). This sample is
+ // not yet linking with all the libraries.
+ JNIEnv* env = /* AttachCurrentThread() */ NULL;
+
+ // This is how you call a java static method from C++.
+ bool foo = base::android::Java_SampleForTests_staticJavaMethod(env);
+
+ // This is how you call a java method from C++. Note that you must have
+ // obtained the jobject somehow.
+ jobject my_java_object = NULL;
+ int bar = base::android::Java_SampleForTests_javaMethod(
+ env, my_java_object, 1, 2);
+
+ return 0;
+}
diff --git a/src/base/android/jni_helper.cc b/src/base/android/jni_helper.cc
new file mode 100644
index 0000000..c0833c9
--- /dev/null
+++ b/src/base/android/jni_helper.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_helper.h"
+
+#include "base/android/jni_android.h"
+#include "base/logging.h"
+
+using base::android::AttachCurrentThread;
+
+JavaObjectWeakGlobalRef::JavaObjectWeakGlobalRef()
+ : obj_(NULL) {
+}
+
+JavaObjectWeakGlobalRef::JavaObjectWeakGlobalRef(
+ const JavaObjectWeakGlobalRef& orig) {
+ Assign(orig);
+}
+
+JavaObjectWeakGlobalRef::JavaObjectWeakGlobalRef(JNIEnv* env, jobject obj)
+ : obj_(env->NewWeakGlobalRef(obj)) {
+ DCHECK(obj_);
+}
+
+JavaObjectWeakGlobalRef::~JavaObjectWeakGlobalRef() {
+ reset();
+}
+
+void JavaObjectWeakGlobalRef::operator=(const JavaObjectWeakGlobalRef& rhs) {
+ Assign(rhs);
+}
+
+void JavaObjectWeakGlobalRef::reset() {
+ if (obj_) {
+ AttachCurrentThread()->DeleteWeakGlobalRef(obj_);
+ obj_ = NULL;
+ }
+}
+
+base::android::ScopedJavaLocalRef<jobject>
+ JavaObjectWeakGlobalRef::get(JNIEnv* env) const {
+ return GetRealObject(env, obj_);
+}
+
+base::android::ScopedJavaLocalRef<jobject> GetRealObject(
+ JNIEnv* env, jweak obj) {
+ jobject real = NULL;
+ if (obj) {
+ real = env->NewLocalRef(obj);
+ if (!real)
+ DLOG(ERROR) << "The real object has been deleted!";
+ }
+ return base::android::ScopedJavaLocalRef<jobject>(env, real);
+}
+
+void JavaObjectWeakGlobalRef::Assign(const JavaObjectWeakGlobalRef& other) {
+ JNIEnv* env = AttachCurrentThread();
+ obj_ = env->NewWeakGlobalRef(other.obj_);
+}
diff --git a/src/base/android/jni_helper.h b/src/base/android/jni_helper.h
new file mode 100644
index 0000000..895bf95
--- /dev/null
+++ b/src/base/android/jni_helper.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_JNI_HELPER_H_
+#define BASE_ANDROID_JNI_HELPER_H_
+
+#include <jni.h>
+
+#include "base/base_export.h"
+#include "base/android/scoped_java_ref.h"
+
+// Manages WeakGlobalRef lifecycle.
+// This class is not thread-safe w.r.t. get() and reset(). Multiple threads may
+// safely use get() concurrently, but if the user calls reset() (or of course,
+// calls the destructor) they'll need to provide their own synchronization.
+class BASE_EXPORT JavaObjectWeakGlobalRef {
+ public:
+ JavaObjectWeakGlobalRef();
+ JavaObjectWeakGlobalRef(const JavaObjectWeakGlobalRef& orig);
+ JavaObjectWeakGlobalRef(JNIEnv* env, jobject obj);
+ virtual ~JavaObjectWeakGlobalRef();
+
+ void operator=(const JavaObjectWeakGlobalRef& rhs);
+
+ base::android::ScopedJavaLocalRef<jobject> get(JNIEnv* env) const;
+
+ void reset();
+
+ private:
+ void Assign(const JavaObjectWeakGlobalRef& rhs);
+
+ jweak obj_;
+};
+
+// Get the real object stored in the weak reference returned as a
+// ScopedJavaLocalRef.
+BASE_EXPORT base::android::ScopedJavaLocalRef<jobject> GetRealObject(
+ JNIEnv* env, jweak obj);
+
+#endif // BASE_ANDROID_JNI_HELPER_H_
diff --git a/src/base/android/jni_registrar.cc b/src/base/android/jni_registrar.cc
new file mode 100644
index 0000000..696924a
--- /dev/null
+++ b/src/base/android/jni_registrar.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_registrar.h"
+
+#include "base/logging.h"
+#include "base/android/jni_android.h"
+
+namespace base {
+namespace android {
+
+bool RegisterNativeMethods(JNIEnv* env,
+ const RegistrationMethod* method,
+ size_t count) {
+ const RegistrationMethod* end = method + count;
+ while (method != end) {
+ if (!method->func(env) < 0) {
+ DLOG(ERROR) << method->name << " failed registration!";
+ return false;
+ }
+ method++;
+ }
+ return true;
+}
+
+} // namespace android
+} // namespace base
diff --git a/src/base/android/jni_registrar.h b/src/base/android/jni_registrar.h
new file mode 100644
index 0000000..849d07f
--- /dev/null
+++ b/src/base/android/jni_registrar.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_JNI_REGISTRAR_H_
+#define BASE_ANDROID_JNI_REGISTRAR_H_
+
+#include <jni.h>
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace android {
+
+struct RegistrationMethod;
+
+// Registers the JNI bindings for the specified |method| definition containing
+// |count| elements. Returns whether the registration of the given methods
+// succeeded.
+BASE_EXPORT bool RegisterNativeMethods(JNIEnv* env,
+ const RegistrationMethod* method,
+ size_t count);
+
+} // namespace android
+} // namespace base
+
+#endif // BASE_ANDROID_JNI_REGISTRAR_H_
diff --git a/src/base/android/jni_string.cc b/src/base/android/jni_string.cc
new file mode 100644
index 0000000..ac3975f
--- /dev/null
+++ b/src/base/android/jni_string.cc
@@ -0,0 +1,99 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_string.h"
+
+#include "base/android/jni_android.h"
+#include "base/logging.h"
+#include "base/utf_string_conversions.h"
+
+namespace {
+
+// Internal version that does not use a scoped local pointer.
+jstring ConvertUTF16ToJavaStringImpl(JNIEnv* env,
+ const base::StringPiece16& str) {
+ jstring result = env->NewString(str.data(), str.length());
+ base::android::CheckException(env);
+ return result;
+}
+
+}
+
+namespace base {
+namespace android {
+
+void ConvertJavaStringToUTF8(JNIEnv* env, jstring str, std::string* result) {
+ if (!str) {
+ LOG(WARNING) << "ConvertJavaStringToUTF8 called with null string.";
+ result->clear();
+ return;
+ }
+ // JNI's GetStringUTFChars() returns strings in Java "modified" UTF8, so
+ // instead get the String in UTF16 and convert using chromium's conversion
+ // function that yields plain (non Java-modified) UTF8.
+ const jchar* chars = env->GetStringChars(str, NULL);
+ DCHECK(chars);
+ UTF16ToUTF8(chars, env->GetStringLength(str), result);
+ env->ReleaseStringChars(str, chars);
+ CheckException(env);
+}
+
+std::string ConvertJavaStringToUTF8(JNIEnv* env, jstring str) {
+ std::string result;
+ ConvertJavaStringToUTF8(env, str, &result);
+ return result;
+}
+
+std::string ConvertJavaStringToUTF8(const JavaRef<jstring>& str) {
+ return ConvertJavaStringToUTF8(AttachCurrentThread(), str.obj());
+}
+
+ScopedJavaLocalRef<jstring> ConvertUTF8ToJavaString(
+ JNIEnv* env,
+ const base::StringPiece& str) {
+ // JNI's NewStringUTF expects "modified" UTF8 so instead create the string
+ // via our own UTF16 conversion utility.
+ // Further, Dalvik requires the string passed into NewStringUTF() to come from
+ // a trusted source. We can't guarantee that all UTF8 will be sanitized before
+ // it gets here, so constructing via UTF16 side-steps this issue.
+ // (Dalvik stores strings internally as UTF16 anyway, so there shouldn't be
+ // a significant performance hit by doing it this way).
+ return ScopedJavaLocalRef<jstring>(env, ConvertUTF16ToJavaStringImpl(
+ env, UTF8ToUTF16(str)));
+}
+
+void ConvertJavaStringToUTF16(JNIEnv* env, jstring str, string16* result) {
+ if (!str) {
+ LOG(WARNING) << "ConvertJavaStringToUTF16 called with null string.";
+ result->clear();
+ return;
+ }
+ const jchar* chars = env->GetStringChars(str, NULL);
+ DCHECK(chars);
+ // GetStringChars isn't required to NULL-terminate the strings
+ // it returns, so the length must be explicitly checked.
+ result->assign(chars, env->GetStringLength(str));
+ env->ReleaseStringChars(str, chars);
+ CheckException(env);
+}
+
+string16 ConvertJavaStringToUTF16(JNIEnv* env, jstring str) {
+ string16 result;
+ ConvertJavaStringToUTF16(env, str, &result);
+ return result;
+}
+
+string16 ConvertJavaStringToUTF16(const JavaRef<jstring>& str) {
+ return ConvertJavaStringToUTF16(AttachCurrentThread(), str.obj());
+}
+
+ScopedJavaLocalRef<jstring> ConvertUTF16ToJavaString(
+ JNIEnv* env,
+ const base::StringPiece16& str) {
+ return ScopedJavaLocalRef<jstring>(env,
+ ConvertUTF16ToJavaStringImpl(env, str));
+}
+
+} // namespace android
+} // namespace base
diff --git a/src/base/android/jni_string.h b/src/base/android/jni_string.h
new file mode 100644
index 0000000..222b78d
--- /dev/null
+++ b/src/base/android/jni_string.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_JNI_STRING_H_
+#define BASE_ANDROID_JNI_STRING_H_
+
+#include <jni.h>
+#include <string>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/base_export.h"
+#include "base/string_piece.h"
+
+namespace base {
+namespace android {
+
+// Convert a Java string to UTF8. Returns a std string.
+BASE_EXPORT void ConvertJavaStringToUTF8(JNIEnv* env,
+ jstring str,
+ std::string* result);
+BASE_EXPORT std::string ConvertJavaStringToUTF8(JNIEnv* env, jstring str);
+BASE_EXPORT std::string ConvertJavaStringToUTF8(const JavaRef<jstring>& str);
+
+// Convert a std string to Java string.
+BASE_EXPORT ScopedJavaLocalRef<jstring> ConvertUTF8ToJavaString(
+ JNIEnv* env,
+ const base::StringPiece& str);
+
+// Convert a Java string to UTF16. Returns a string16.
+BASE_EXPORT void ConvertJavaStringToUTF16(JNIEnv* env,
+ jstring str,
+ string16* result);
+BASE_EXPORT string16 ConvertJavaStringToUTF16(JNIEnv* env, jstring str);
+BASE_EXPORT string16 ConvertJavaStringToUTF16(const JavaRef<jstring>& str);
+
+// Convert a string16 to a Java string.
+BASE_EXPORT ScopedJavaLocalRef<jstring> ConvertUTF16ToJavaString(
+ JNIEnv* env,
+ const base::StringPiece16& str);
+
+} // namespace android
+} // namespace base
+
+#endif // BASE_ANDROID_JNI_STRING_H_
diff --git a/src/base/android/jni_string_unittest.cc b/src/base/android/jni_string_unittest.cc
new file mode 100644
index 0000000..59a847e
--- /dev/null
+++ b/src/base/android/jni_string_unittest.cc
@@ -0,0 +1,32 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_string.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+TEST(JniString, BasicConversionsUTF8) {
+ const std::string kSimpleString = "SimpleTest8";
+ JNIEnv* env = AttachCurrentThread();
+ std::string result =
+ ConvertJavaStringToUTF8(ConvertUTF8ToJavaString(env, kSimpleString));
+ EXPECT_EQ(kSimpleString, result);
+}
+
+TEST(JniString, BasicConversionsUTF16) {
+ const string16 kSimpleString = UTF8ToUTF16("SimpleTest16");
+ JNIEnv* env = AttachCurrentThread();
+ string16 result =
+ ConvertJavaStringToUTF16(ConvertUTF16ToJavaString(env, kSimpleString));
+ EXPECT_EQ(kSimpleString, result);
+}
+
+} // namespace android
+} // namespace base
diff --git a/src/base/android/locale_utils.cc b/src/base/android/locale_utils.cc
new file mode 100644
index 0000000..60b8f84
--- /dev/null
+++ b/src/base/android/locale_utils.cc
@@ -0,0 +1,95 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/locale_utils.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "jni/LocaleUtils_jni.h"
+#include "unicode/uloc.h"
+
+namespace base {
+namespace android {
+
+std::string GetDefaultLocale() {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> locale = Java_LocaleUtils_getDefaultLocale(env);
+ return ConvertJavaStringToUTF8(locale);
+}
+
+namespace {
+
+// Common prototype of ICU uloc_getXXX() functions.
+typedef int32_t (*UlocGetComponentFunc)(const char*, char*, int32_t,
+ UErrorCode*);
+
+std::string GetLocaleComponent(const std::string& locale,
+ UlocGetComponentFunc uloc_func,
+ int32_t max_capacity) {
+ std::string result;
+ UErrorCode error = U_ZERO_ERROR;
+ int32_t actual_length = uloc_func(locale.c_str(),
+ WriteInto(&result, max_capacity),
+ max_capacity,
+ &error);
+ DCHECK(U_SUCCESS(error));
+ DCHECK(actual_length < max_capacity);
+ result.resize(actual_length);
+ return result;
+}
+
+ScopedJavaLocalRef<jobject> NewJavaLocale(
+ JNIEnv* env,
+ ScopedJavaLocalRef<jclass> locale_class,
+ jmethodID constructor_id,
+ const std::string& locale) {
+ // TODO(wangxianzhu): Use new Locale API once Android supports scripts.
+ std::string language = GetLocaleComponent(
+ locale, uloc_getLanguage, ULOC_LANG_CAPACITY);
+ std::string country = GetLocaleComponent(
+ locale, uloc_getCountry, ULOC_COUNTRY_CAPACITY);
+ std::string variant = GetLocaleComponent(
+ locale, uloc_getVariant, ULOC_FULLNAME_CAPACITY);
+ return ScopedJavaLocalRef<jobject>(
+ env, env->NewObject(
+ locale_class.obj(), constructor_id,
+ ConvertUTF8ToJavaString(env, language).obj(),
+ ConvertUTF8ToJavaString(env, country).obj(),
+ ConvertUTF8ToJavaString(env, variant).obj()));
+}
+
+} // namespace
+
+string16 GetDisplayNameForLocale(const std::string& locale,
+ const std::string& display_locale) {
+ JNIEnv* env = AttachCurrentThread();
+
+ ScopedJavaLocalRef<jclass> locale_class = GetClass(env, "java/util/Locale");
+ jmethodID constructor_id = MethodID::Get<MethodID::TYPE_INSTANCE>(
+ env, locale_class.obj(), "<init>",
+ "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
+ ScopedJavaLocalRef<jobject> java_locale = NewJavaLocale(
+ env, locale_class, constructor_id, locale);
+ ScopedJavaLocalRef<jobject> java_display_locale = NewJavaLocale(
+ env, locale_class, constructor_id, display_locale);
+
+ jmethodID method_id = MethodID::Get<MethodID::TYPE_INSTANCE>(
+ env, locale_class.obj(), "getDisplayName",
+ "(Ljava/util/Locale;)Ljava/lang/String;");
+ ScopedJavaLocalRef<jstring> java_result(
+ env,
+ static_cast<jstring>(env->CallObjectMethod(java_locale.obj(), method_id,
+ java_display_locale.obj())));
+ return ConvertJavaStringToUTF16(java_result);
+}
+
+bool RegisterLocaleUtils(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+} // namespace android
+} // namespace base
diff --git a/src/base/android/locale_utils.h b/src/base/android/locale_utils.h
new file mode 100644
index 0000000..cef39f4
--- /dev/null
+++ b/src/base/android/locale_utils.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_LOCALE_UTILS_H_
+#define BASE_ANDROID_LOCALE_UTILS_H_
+
+#include <jni.h>
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/string16.h"
+
+namespace base {
+namespace android {
+
+// Return the current default locale of the device.
+BASE_EXPORT std::string GetDefaultLocale();
+
+BASE_EXPORT string16 GetDisplayNameForLocale(const std::string& locale,
+ const std::string& display_locale);
+
+bool RegisterLocaleUtils(JNIEnv* env);
+
+} // namespace android
+} // namespace base
+
+#endif // BASE_ANDROID_LOCALE_UTILS_H_
diff --git a/src/base/android/path_service_android.cc b/src/base/android/path_service_android.cc
new file mode 100644
index 0000000..a9bf92d
--- /dev/null
+++ b/src/base/android/path_service_android.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/path_service_android.h"
+
+#include "base/file_path.h"
+#include "base/path_service.h"
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "jni/PathService_jni.h"
+
+namespace base {
+namespace android {
+
+void Override(JNIEnv* env, jclass clazz, jint what, jstring path) {
+ FilePath file_path(ConvertJavaStringToUTF8(env, path));
+ PathService::Override(what, file_path);
+}
+
+bool RegisterPathService(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+} // namespace android
+} // namespace base
diff --git a/src/base/android/path_service_android.h b/src/base/android/path_service_android.h
new file mode 100644
index 0000000..26040f9
--- /dev/null
+++ b/src/base/android/path_service_android.h
@@ -0,0 +1,18 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_PATH_SERVICE_ANDROID_H_
+#define BASE_ANDROID_PATH_SERVICE_ANDROID_H_
+
+#include <jni.h>
+
+namespace base {
+namespace android {
+
+bool RegisterPathService(JNIEnv* env);
+
+} // namespace android
+} // namespace base
+
+#endif // BASE_ANDROID_PATH_SERVICE_ANDROID_H_
diff --git a/src/base/android/path_utils.cc b/src/base/android/path_utils.cc
new file mode 100644
index 0000000..3d86177
--- /dev/null
+++ b/src/base/android/path_utils.cc
@@ -0,0 +1,67 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/path_utils.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/file_path.h"
+
+#include "jni/PathUtils_jni.h"
+
+namespace base {
+namespace android {
+
+bool GetDataDirectory(FilePath* result) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> path =
+ Java_PathUtils_getDataDirectory(env, GetApplicationContext());
+ FilePath data_path(ConvertJavaStringToUTF8(path));
+ *result = data_path;
+ return true;
+}
+
+bool GetCacheDirectory(FilePath* result) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> path =
+ Java_PathUtils_getCacheDirectory(env, GetApplicationContext());
+ FilePath cache_path(ConvertJavaStringToUTF8(path));
+ *result = cache_path;
+ return true;
+}
+
+bool GetDownloadsDirectory(FilePath* result) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> path =
+ Java_PathUtils_getDownloadsDirectory(env, GetApplicationContext());
+ FilePath downloads_path(ConvertJavaStringToUTF8(path));
+ *result = downloads_path;
+ return true;
+}
+
+bool GetNativeLibraryDirectory(FilePath* result) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> path =
+ Java_PathUtils_getNativeLibraryDirectory(env, GetApplicationContext());
+ FilePath library_path(ConvertJavaStringToUTF8(path));
+ *result = library_path;
+ return true;
+}
+
+bool GetExternalStorageDirectory(FilePath* result) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> path =
+ Java_PathUtils_getExternalStorageDirectory(env);
+ FilePath storage_path(ConvertJavaStringToUTF8(path));
+ *result = storage_path;
+ return true;
+}
+
+bool RegisterPathUtils(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+} // namespace android
+} // namespace base
diff --git a/src/base/android/path_utils.h b/src/base/android/path_utils.h
new file mode 100644
index 0000000..78f0267
--- /dev/null
+++ b/src/base/android/path_utils.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_PATH_UTILS_H_
+#define BASE_ANDROID_PATH_UTILS_H_
+
+#include <jni.h>
+
+#include "base/base_export.h"
+
+class FilePath;
+
+namespace base {
+namespace android {
+
+// Retrieves the absolute path to the data directory of the current
+// application. The result is placed in the FilePath pointed to by 'result'.
+// This method is dedicated for base_paths_android.c, Using
+// PathService::Get(base::DIR_ANDROID_APP_DATA, ...) gets the data dir.
+BASE_EXPORT bool GetDataDirectory(FilePath* result);
+
+// Retrieves the absolute path to the cache directory. The result is placed in
+// the FilePath pointed to by 'result'. This method is dedicated for
+// base_paths_android.c, Using PathService::Get(base::DIR_CACHE, ...) gets the
+// cache dir.
+BASE_EXPORT bool GetCacheDirectory(FilePath* result);
+
+// Retrieves the path to the public downloads directory. The result is placed
+// in the FilePath pointed to by 'result'.
+bool GetDownloadsDirectory(FilePath* result);
+
+// Retrieves the path to the native JNI libraries via
+// ApplicationInfo.nativeLibraryDir on the Java side. The result is placed in
+// the FilePath pointed to by 'result'.
+BASE_EXPORT bool GetNativeLibraryDirectory(FilePath* result);
+
+// Retrieves the absolute path to the external storage directory. The result
+// is placed in the FilePath pointed to by 'result'.
+BASE_EXPORT bool GetExternalStorageDirectory(FilePath* result);
+
+bool RegisterPathUtils(JNIEnv* env);
+
+} // namespace android
+} // namespace base
+
+#endif // BASE_ANDROID_PATH_UTILS_H_
diff --git a/src/base/android/path_utils_unittest.cc b/src/base/android/path_utils_unittest.cc
new file mode 100644
index 0000000..636e3fa
--- /dev/null
+++ b/src/base/android/path_utils_unittest.cc
@@ -0,0 +1,46 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/path_utils.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+typedef testing::Test PathUtilsTest;
+
+TEST_F(PathUtilsTest, TestGetDataDirectory) {
+ // The string comes from the Java side and depends on the APK
+ // we are running in. Assumes that we are packaged in
+ // org.chromium.native_test
+ FilePath path;
+ GetDataDirectory(&path);
+ EXPECT_STREQ("/data/data/org.chromium.native_test/app_chrome",
+ path.value().c_str());
+}
+
+TEST_F(PathUtilsTest, TestGetCacheDirectory) {
+ // The string comes from the Java side and depends on the APK
+ // we are running in. Assumes that we are packaged in
+ // org.chromium.native_test
+ FilePath path;
+ GetCacheDirectory(&path);
+ EXPECT_STREQ("/data/data/org.chromium.native_test/cache",
+ path.value().c_str());
+}
+
+TEST_F(PathUtilsTest, TestGetNativeLibraryDirectory) {
+ // The string comes from the Java side and depends on the APK
+ // we are running in. Assumes that the directory contains
+ // the base tests shared object.
+ FilePath path;
+ GetNativeLibraryDirectory(&path);
+ EXPECT_TRUE(file_util::PathExists(path.Append(("libbase_unittests.so"))));
+}
+
+} // namespace android
+} // namespace base
diff --git a/src/base/android/scoped_java_ref.cc b/src/base/android/scoped_java_ref.cc
new file mode 100644
index 0000000..21b466e
--- /dev/null
+++ b/src/base/android/scoped_java_ref.cc
@@ -0,0 +1,73 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/scoped_java_ref.h"
+
+#include "base/android/jni_android.h"
+#include "base/logging.h"
+
+namespace base {
+namespace android {
+
+JavaRef<jobject>::JavaRef() : obj_(NULL) {}
+
+JavaRef<jobject>::JavaRef(JNIEnv* env, jobject obj) : obj_(obj) {
+ if (obj) {
+ DCHECK(env && env->GetObjectRefType(obj) == JNILocalRefType);
+ }
+}
+
+JavaRef<jobject>::~JavaRef() {
+}
+
+JNIEnv* JavaRef<jobject>::SetNewLocalRef(JNIEnv* env, jobject obj) {
+ if (!env) {
+ env = AttachCurrentThread();
+ } else {
+ DCHECK_EQ(env, AttachCurrentThread()); // Is |env| on correct thread.
+ }
+ if (obj)
+ obj = env->NewLocalRef(obj);
+ if (obj_)
+ env->DeleteLocalRef(obj_);
+ obj_ = obj;
+ return env;
+}
+
+void JavaRef<jobject>::SetNewGlobalRef(JNIEnv* env, jobject obj) {
+ if (!env) {
+ env = AttachCurrentThread();
+ } else {
+ DCHECK_EQ(env, AttachCurrentThread()); // Is |env| on correct thread.
+ }
+ if (obj)
+ obj = env->NewGlobalRef(obj);
+ if (obj_)
+ env->DeleteGlobalRef(obj_);
+ obj_ = obj;
+}
+
+void JavaRef<jobject>::ResetLocalRef(JNIEnv* env) {
+ if (obj_) {
+ DCHECK_EQ(env, AttachCurrentThread()); // Is |env| on correct thread.
+ env->DeleteLocalRef(obj_);
+ obj_ = NULL;
+ }
+}
+
+void JavaRef<jobject>::ResetGlobalRef() {
+ if (obj_) {
+ AttachCurrentThread()->DeleteGlobalRef(obj_);
+ obj_ = NULL;
+ }
+}
+
+jobject JavaRef<jobject>::ReleaseInternal() {
+ jobject obj = obj_;
+ obj_ = NULL;
+ return obj;
+}
+
+} // namespace android
+} // namespace base
diff --git a/src/base/android/scoped_java_ref.h b/src/base/android/scoped_java_ref.h
new file mode 100644
index 0000000..a5d71e2
--- /dev/null
+++ b/src/base/android/scoped_java_ref.h
@@ -0,0 +1,198 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_SCOPED_JAVA_REF_H_
+#define BASE_ANDROID_SCOPED_JAVA_REF_H_
+
+#include <jni.h>
+#include <stddef.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace android {
+
+// Forward declare the generic java reference template class.
+template<typename T> class JavaRef;
+
+// Template specialization of JavaRef, which acts as the base class for all
+// other JavaRef<> template types. This allows you to e.g. pass
+// ScopedJavaLocalRef<jstring> into a function taking const JavaRef<jobject>&
+template<>
+class BASE_EXPORT JavaRef<jobject> {
+ public:
+ jobject obj() const { return obj_; }
+
+ bool is_null() const { return obj_ == NULL; }
+
+ protected:
+ // Initializes a NULL reference.
+ JavaRef();
+
+ // Takes ownership of the |obj| reference passed; requires it to be a local
+ // reference type.
+ JavaRef(JNIEnv* env, jobject obj);
+
+ ~JavaRef();
+
+ // The following are implementation detail convenience methods, for
+ // use by the sub-classes.
+ JNIEnv* SetNewLocalRef(JNIEnv* env, jobject obj);
+ void SetNewGlobalRef(JNIEnv* env, jobject obj);
+ void ResetLocalRef(JNIEnv* env);
+ void ResetGlobalRef();
+ jobject ReleaseInternal();
+
+ private:
+ jobject obj_;
+
+ DISALLOW_COPY_AND_ASSIGN(JavaRef);
+};
+
+// Generic base class for ScopedJavaLocalRef and ScopedJavaGlobalRef. Useful
+// for allowing functions to accept a reference without having to mandate
+// whether it is a local or global type.
+template<typename T>
+class JavaRef : public JavaRef<jobject> {
+ public:
+ T obj() const { return static_cast<T>(JavaRef<jobject>::obj()); }
+
+ protected:
+ JavaRef() {}
+ ~JavaRef() {}
+
+ JavaRef(JNIEnv* env, T obj) : JavaRef<jobject>(env, obj) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(JavaRef);
+};
+
+// Holds a local reference to a Java object. The local reference is scoped
+// to the lifetime of this object.
+// Instances of this class may hold onto any JNIEnv passed into it until
+// destroyed. Therefore, since a JNIEnv is only suitable for use on a single
+// thread, objects of this class must be created, used, and destroyed, on a
+// single thread.
+// Therefore, this class should only be used as a stack-based object and from a
+// single thread. If you wish to have the reference outlive the current
+// callstack (e.g. as a class member) or you wish to pass it across threads,
+// use a ScopedJavaGlobalRef instead.
+template<typename T>
+class ScopedJavaLocalRef : public JavaRef<T> {
+ public:
+ ScopedJavaLocalRef() : env_(NULL) {}
+
+ // Non-explicit copy constructor, to allow ScopedJavaLocalRef to be returned
+ // by value as this is the normal usage pattern.
+ ScopedJavaLocalRef(const ScopedJavaLocalRef<T>& other)
+ : env_(other.env_) {
+ this->SetNewLocalRef(env_, other.obj());
+ }
+
+ template<typename U>
+ explicit ScopedJavaLocalRef(const U& other)
+ : env_(NULL) {
+ this->Reset(other);
+ }
+
+ // Assumes that |obj| is a local reference to a Java object and takes
+ // ownership of this local reference.
+ ScopedJavaLocalRef(JNIEnv* env, T obj) : JavaRef<T>(env, obj), env_(env) {}
+
+ ~ScopedJavaLocalRef() {
+ this->Reset();
+ }
+
+ // Overloaded assignment operator defined for consistency with the implicit
+ // copy constructor.
+ void operator=(const ScopedJavaLocalRef<T>& other) {
+ this->Reset(other);
+ }
+
+ void Reset() {
+ this->ResetLocalRef(env_);
+ }
+
+ template<typename U>
+ void Reset(const ScopedJavaLocalRef<U>& other) {
+ // We can copy over env_ here as |other| instance must be from the same
+ // thread as |this| local ref. (See class comment for multi-threading
+ // limitations, and alternatives).
+ this->Reset(other.env_, other.obj());
+ }
+
+ template<typename U>
+ void Reset(const U& other) {
+ // If |env_| was not yet set (is still NULL) it will be attached to the
+ // current thread in SetNewLocalRef().
+ this->Reset(env_, other.obj());
+ }
+
+ template<typename U>
+ void Reset(JNIEnv* env, U obj) {
+ implicit_cast<T>(obj); // Ensure U is assignable to T
+ env_ = this->SetNewLocalRef(env, obj);
+ }
+
+ // Releases the local reference to the caller. The caller *must* delete the
+ // local reference when it is done with it.
+ T Release() {
+ return static_cast<T>(this->ReleaseInternal());
+ }
+
+ private:
+ // This class is only good for use on the thread it was created on so
+ // it's safe to cache the non-threadsafe JNIEnv* inside this object.
+ JNIEnv* env_;
+};
+
+// Holds a global reference to a Java object. The global reference is scoped
+// to the lifetime of this object. This class does not hold onto any JNIEnv*
+// passed to it, hence it is safe to use across threads (within the constraints
+// imposed by the underlying Java object that it references).
+template<typename T>
+class ScopedJavaGlobalRef : public JavaRef<T> {
+ public:
+ ScopedJavaGlobalRef() {}
+
+ explicit ScopedJavaGlobalRef(const ScopedJavaGlobalRef<T>& other) {
+ this->Reset(other);
+ }
+
+ template<typename U>
+ explicit ScopedJavaGlobalRef(const U& other) {
+ this->Reset(other);
+ }
+
+ ~ScopedJavaGlobalRef() {
+ this->Reset();
+ }
+
+ void Reset() {
+ this->ResetGlobalRef();
+ }
+
+ template<typename U>
+ void Reset(const U& other) {
+ this->Reset(NULL, other.obj());
+ }
+
+ template<typename U>
+ void Reset(JNIEnv* env, U obj) {
+ implicit_cast<T>(obj); // Ensure U is assignable to T
+ this->SetNewGlobalRef(env, obj);
+ }
+
+ // Releases the global reference to the caller. The caller *must* delete the
+ // global reference when it is done with it.
+ T Release() {
+ return static_cast<T>(this->ReleaseInternal());
+ }
+};
+
+} // namespace android
+} // namespace base
+
+#endif // BASE_ANDROID_SCOPED_JAVA_REF_H_
diff --git a/src/base/android/scoped_java_ref_unittest.cc b/src/base/android/scoped_java_ref_unittest.cc
new file mode 100644
index 0000000..36f253c
--- /dev/null
+++ b/src/base/android/scoped_java_ref_unittest.cc
@@ -0,0 +1,122 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/scoped_java_ref.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+namespace {
+int g_local_refs = 0;
+int g_global_refs = 0;
+
+const JNINativeInterface* g_previous_functions;
+
+jobject NewGlobalRef(JNIEnv* env, jobject obj) {
+ ++g_global_refs;
+ return g_previous_functions->NewGlobalRef(env, obj);
+}
+
+void DeleteGlobalRef(JNIEnv* env, jobject obj) {
+ --g_global_refs;
+ return g_previous_functions->DeleteGlobalRef(env, obj);
+}
+
+jobject NewLocalRef(JNIEnv* env, jobject obj) {
+ ++g_local_refs;
+ return g_previous_functions->NewLocalRef(env, obj);
+}
+
+void DeleteLocalRef(JNIEnv* env, jobject obj) {
+ --g_local_refs;
+ return g_previous_functions->DeleteLocalRef(env, obj);
+}
+} // namespace
+
+class ScopedJavaRefTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ g_local_refs = 0;
+ g_global_refs = 0;
+ JNIEnv* env = AttachCurrentThread();
+ g_previous_functions = env->functions;
+ hooked_functions = *g_previous_functions;
+ env->functions = &hooked_functions;
+ // We inject our own functions in JNINativeInterface so we can keep track
+ // of the reference counting ourselves.
+ hooked_functions.NewGlobalRef = &NewGlobalRef;
+ hooked_functions.DeleteGlobalRef = &DeleteGlobalRef;
+ hooked_functions.NewLocalRef = &NewLocalRef;
+ hooked_functions.DeleteLocalRef = &DeleteLocalRef;
+ }
+
+ virtual void TearDown() {
+ JNIEnv* env = AttachCurrentThread();
+ env->functions = g_previous_functions;
+ }
+ // From JellyBean release, the instance of this struct provided in JNIEnv is
+ // read-only, so we deep copy it to allow individual functions to be hooked.
+ JNINativeInterface hooked_functions;
+};
+
+// The main purpose of this is testing the various conversions compile.
+TEST_F(ScopedJavaRefTest, Conversions) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> str = ConvertUTF8ToJavaString(env, "string");
+ ScopedJavaGlobalRef<jstring> global(str);
+ {
+ ScopedJavaGlobalRef<jobject> global_obj(str);
+ ScopedJavaLocalRef<jobject> local_obj(global);
+ const JavaRef<jobject>& obj_ref1(str);
+ const JavaRef<jobject>& obj_ref2(global);
+ EXPECT_TRUE(env->IsSameObject(obj_ref1.obj(), obj_ref2.obj()));
+ EXPECT_TRUE(env->IsSameObject(global_obj.obj(), obj_ref2.obj()));
+ }
+ global.Reset(str);
+ const JavaRef<jstring>& str_ref = str;
+ EXPECT_EQ("string", ConvertJavaStringToUTF8(str_ref));
+ str.Reset();
+}
+
+TEST_F(ScopedJavaRefTest, RefCounts) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> str;
+ // The ConvertJavaStringToUTF8 below creates a new string that would normally
+ // return a local ref. We simulate that by starting the g_local_refs count at
+ // 1.
+ g_local_refs = 1;
+ str.Reset(ConvertUTF8ToJavaString(env, "string"));
+ EXPECT_EQ(1, g_local_refs);
+ EXPECT_EQ(0, g_global_refs);
+ {
+ ScopedJavaGlobalRef<jstring> global_str(str);
+ ScopedJavaGlobalRef<jobject> global_obj(global_str);
+ EXPECT_EQ(1, g_local_refs);
+ EXPECT_EQ(2, g_global_refs);
+
+ ScopedJavaLocalRef<jstring> str2(env, str.Release());
+ EXPECT_EQ(1, g_local_refs);
+ {
+ ScopedJavaLocalRef<jstring> str3(str2);
+ EXPECT_EQ(2, g_local_refs);
+ }
+ EXPECT_EQ(1, g_local_refs);
+ str2.Reset();
+ EXPECT_EQ(0, g_local_refs);
+ global_str.Reset();
+ EXPECT_EQ(1, g_global_refs);
+ ScopedJavaGlobalRef<jobject> global_obj2(global_obj);
+ EXPECT_EQ(2, g_global_refs);
+ }
+
+ EXPECT_EQ(0, g_local_refs);
+ EXPECT_EQ(0, g_global_refs);
+}
+
+} // namespace android
+} // namespace base
diff --git a/src/base/at_exit.cc b/src/base/at_exit.cc
new file mode 100644
index 0000000..0fba355
--- /dev/null
+++ b/src/base/at_exit.cc
@@ -0,0 +1,82 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/at_exit.h"
+
+#include <stddef.h>
+#include <ostream>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+
+namespace base {
+
+// Keep a stack of registered AtExitManagers. We always operate on the most
+// recent, and we should never have more than one outside of testing (for a
+// statically linked version of this library). Testing may use the shadow
+// version of the constructor, and if we are building a dynamic library we may
+// end up with multiple AtExitManagers on the same process. We don't protect
+// this for thread-safe access, since it will only be modified in testing.
+static AtExitManager* g_top_manager = NULL;
+
+AtExitManager::AtExitManager() : next_manager_(g_top_manager) {
+// If multiple modules instantiate AtExitManagers they'll end up living in this
+// module... they have to coexist.
+#if !defined(COMPONENT_BUILD)
+ DCHECK(!g_top_manager);
+#endif
+ g_top_manager = this;
+}
+
+AtExitManager::~AtExitManager() {
+ if (!g_top_manager) {
+ NOTREACHED() << "Tried to ~AtExitManager without an AtExitManager";
+ return;
+ }
+ DCHECK_EQ(this, g_top_manager);
+
+ ProcessCallbacksNow();
+ g_top_manager = next_manager_;
+}
+
+// static
+void AtExitManager::RegisterCallback(AtExitCallbackType func, void* param) {
+ DCHECK(func);
+ RegisterTask(base::Bind(func, param));
+}
+
+// static
+void AtExitManager::RegisterTask(base::Closure task) {
+ if (!g_top_manager) {
+ NOTREACHED() << "Tried to RegisterCallback without an AtExitManager";
+ return;
+ }
+
+ AutoLock lock(g_top_manager->lock_);
+ g_top_manager->stack_.push(task);
+}
+
+// static
+void AtExitManager::ProcessCallbacksNow() {
+ if (!g_top_manager) {
+ NOTREACHED() << "Tried to ProcessCallbacksNow without an AtExitManager";
+ return;
+ }
+
+ AutoLock lock(g_top_manager->lock_);
+
+ while (!g_top_manager->stack_.empty()) {
+ base::Closure task = g_top_manager->stack_.top();
+ task.Run();
+ g_top_manager->stack_.pop();
+ }
+}
+
+AtExitManager::AtExitManager(bool shadow) : next_manager_(g_top_manager) {
+ DCHECK(shadow || !g_top_manager);
+ g_top_manager = this;
+}
+
+} // namespace base
diff --git a/src/base/at_exit.h b/src/base/at_exit.h
new file mode 100644
index 0000000..6b28ae9
--- /dev/null
+++ b/src/base/at_exit.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_AT_EXIT_H_
+#define BASE_AT_EXIT_H_
+
+#include <stack>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+// This class provides a facility similar to the CRT atexit(), except that
+// we control when the callbacks are executed. Under Windows for a DLL they
+// happen at a really bad time and under the loader lock. This facility is
+// mostly used by base::Singleton.
+//
+// The usage is simple. Early in the main() or WinMain() scope create an
+// AtExitManager object on the stack:
+// int main(...) {
+// base::AtExitManager exit_manager;
+//
+// }
+// When the exit_manager object goes out of scope, all the registered
+// callbacks and singleton destructors will be called.
+
+class BASE_EXPORT AtExitManager {
+ public:
+ typedef void (*AtExitCallbackType)(void*);
+
+ AtExitManager();
+
+ // The dtor calls all the registered callbacks. Do not try to register more
+ // callbacks after this point.
+ ~AtExitManager();
+
+ // Registers the specified function to be called at exit. The prototype of
+ // the callback function is void func(void*).
+ static void RegisterCallback(AtExitCallbackType func, void* param);
+
+ // Registers the specified task to be called at exit.
+ static void RegisterTask(base::Closure task);
+
+ // Calls the functions registered with RegisterCallback in LIFO order. It
+ // is possible to register new callbacks after calling this function.
+ static void ProcessCallbacksNow();
+
+ protected:
+ // This constructor will allow this instance of AtExitManager to be created
+ // even if one already exists. This should only be used for testing!
+ // AtExitManagers are kept on a global stack, and it will be removed during
+ // destruction. This allows you to shadow another AtExitManager.
+ explicit AtExitManager(bool shadow);
+
+ private:
+ base::Lock lock_;
+ std::stack<base::Closure> stack_;
+ AtExitManager* next_manager_; // Stack of managers to allow shadowing.
+
+ DISALLOW_COPY_AND_ASSIGN(AtExitManager);
+};
+
+#if defined(__LB_SHELL__) || defined(UNIT_TEST) || defined(COBALT)
+class ShadowingAtExitManager : public AtExitManager {
+ public:
+ ShadowingAtExitManager() : AtExitManager(true) {}
+};
+#endif // defined(UNIT_TEST)
+
+} // namespace base
+
+#endif // BASE_AT_EXIT_H_
diff --git a/src/base/at_exit_unittest.cc b/src/base/at_exit_unittest.cc
new file mode 100644
index 0000000..cda7340
--- /dev/null
+++ b/src/base/at_exit_unittest.cc
@@ -0,0 +1,87 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/at_exit.h"
+#include "base/bind.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+int g_test_counter_1 = 0;
+int g_test_counter_2 = 0;
+
+void IncrementTestCounter1(void* unused) {
+ ++g_test_counter_1;
+}
+
+void IncrementTestCounter2(void* unused) {
+ ++g_test_counter_2;
+}
+
+void ZeroTestCounters() {
+ g_test_counter_1 = 0;
+ g_test_counter_2 = 0;
+}
+
+void ExpectCounter1IsZero(void* unused) {
+ EXPECT_EQ(0, g_test_counter_1);
+}
+
+void ExpectParamIsNull(void* param) {
+ EXPECT_EQ(static_cast<void*>(NULL), param);
+}
+
+void ExpectParamIsCounter(void* param) {
+ EXPECT_EQ(&g_test_counter_1, param);
+}
+
+} // namespace
+
+class AtExitTest : public testing::Test {
+ private:
+ // Don't test the global AtExitManager, because asking it to process its
+ // AtExit callbacks can ruin the global state that other tests may depend on.
+ base::ShadowingAtExitManager exit_manager_;
+};
+
+TEST_F(AtExitTest, Basic) {
+ ZeroTestCounters();
+ base::AtExitManager::RegisterCallback(&IncrementTestCounter1, NULL);
+ base::AtExitManager::RegisterCallback(&IncrementTestCounter2, NULL);
+ base::AtExitManager::RegisterCallback(&IncrementTestCounter1, NULL);
+
+ EXPECT_EQ(0, g_test_counter_1);
+ EXPECT_EQ(0, g_test_counter_2);
+ base::AtExitManager::ProcessCallbacksNow();
+ EXPECT_EQ(2, g_test_counter_1);
+ EXPECT_EQ(1, g_test_counter_2);
+}
+
+TEST_F(AtExitTest, LIFOOrder) {
+ ZeroTestCounters();
+ base::AtExitManager::RegisterCallback(&IncrementTestCounter1, NULL);
+ base::AtExitManager::RegisterCallback(&ExpectCounter1IsZero, NULL);
+ base::AtExitManager::RegisterCallback(&IncrementTestCounter2, NULL);
+
+ EXPECT_EQ(0, g_test_counter_1);
+ EXPECT_EQ(0, g_test_counter_2);
+ base::AtExitManager::ProcessCallbacksNow();
+ EXPECT_EQ(1, g_test_counter_1);
+ EXPECT_EQ(1, g_test_counter_2);
+}
+
+TEST_F(AtExitTest, Param) {
+ base::AtExitManager::RegisterCallback(&ExpectParamIsNull, NULL);
+ base::AtExitManager::RegisterCallback(&ExpectParamIsCounter,
+ &g_test_counter_1);
+ base::AtExitManager::ProcessCallbacksNow();
+}
+
+TEST_F(AtExitTest, Task) {
+ ZeroTestCounters();
+ base::AtExitManager::RegisterTask(base::Bind(&ExpectParamIsCounter,
+ &g_test_counter_1));
+ base::AtExitManager::ProcessCallbacksNow();
+}
diff --git a/src/base/atomic_ref_count.h b/src/base/atomic_ref_count.h
new file mode 100644
index 0000000..5130860
--- /dev/null
+++ b/src/base/atomic_ref_count.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is a low level implementation of atomic semantics for reference
+// counting. Please use base/memory/ref_counted.h directly instead.
+//
+// The implementation includes annotations to avoid some false positives
+// when using data race detection tools.
+
+#ifndef BASE_ATOMIC_REF_COUNT_H_
+#define BASE_ATOMIC_REF_COUNT_H_
+
+#include "base/atomicops.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+
+namespace base {
+
+typedef subtle::Atomic32 AtomicRefCount;
+
+// Increment a reference count by "increment", which must exceed 0.
+inline void AtomicRefCountIncN(volatile AtomicRefCount *ptr,
+ AtomicRefCount increment) {
+ subtle::NoBarrier_AtomicIncrement(ptr, increment);
+}
+
+// Decrement a reference count by "decrement", which must exceed 0,
+// and return whether the result is non-zero.
+// Insert barriers to ensure that state written before the reference count
+// became zero will be visible to a thread that has just made the count zero.
+inline bool AtomicRefCountDecN(volatile AtomicRefCount *ptr,
+ AtomicRefCount decrement) {
+ ANNOTATE_HAPPENS_BEFORE(ptr);
+ bool res = (subtle::Barrier_AtomicIncrement(ptr, -decrement) != 0);
+ if (!res) {
+ ANNOTATE_HAPPENS_AFTER(ptr);
+ }
+ return res;
+}
+
+// Increment a reference count by 1.
+inline void AtomicRefCountInc(volatile AtomicRefCount *ptr) {
+ base::AtomicRefCountIncN(ptr, 1);
+}
+
+// Decrement a reference count by 1 and return whether the result is non-zero.
+// Insert barriers to ensure that state written before the reference count
+// became zero will be visible to a thread that has just made the count zero.
+inline bool AtomicRefCountDec(volatile AtomicRefCount *ptr) {
+ return base::AtomicRefCountDecN(ptr, 1);
+}
+
+// Return whether the reference count is one. If the reference count is used
+// in the conventional way, a refrerence count of 1 implies that the current
+// thread owns the reference and no other thread shares it. This call performs
+// the test for a reference count of one, and performs the memory barrier
+// needed for the owning thread to act on the object, knowing that it has
+// exclusive access to the object.
+inline bool AtomicRefCountIsOne(volatile AtomicRefCount *ptr) {
+ bool res = (subtle::Acquire_Load(ptr) == 1);
+ if (res) {
+ ANNOTATE_HAPPENS_AFTER(ptr);
+ }
+ return res;
+}
+
+// Return whether the reference count is zero. With conventional object
+// referencing counting, the object will be destroyed, so the reference count
+// should never be zero. Hence this is generally used for a debug check.
+inline bool AtomicRefCountIsZero(volatile AtomicRefCount *ptr) {
+ bool res = (subtle::Acquire_Load(ptr) == 0);
+ if (res) {
+ ANNOTATE_HAPPENS_AFTER(ptr);
+ }
+ return res;
+}
+
+} // namespace base
+
+#endif // BASE_ATOMIC_REF_COUNT_H_
diff --git a/src/base/atomic_sequence_num.h b/src/base/atomic_sequence_num.h
new file mode 100644
index 0000000..7bf2778
--- /dev/null
+++ b/src/base/atomic_sequence_num.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ATOMIC_SEQUENCE_NUM_H_
+#define BASE_ATOMIC_SEQUENCE_NUM_H_
+
+#include "base/atomicops.h"
+#include "base/basictypes.h"
+
+namespace base {
+
+class AtomicSequenceNumber;
+
+// Static (POD) AtomicSequenceNumber that MUST be used in global scope (or
+// non-function scope) ONLY. This implementation does not generate any static
+// initializer. Note that it does not implement any constructor which means
+// that its fields are not initialized except when it is stored in the global
+// data section (.data in ELF). If you want to allocate an atomic sequence
+// number on the stack (or heap), please use the AtomicSequenceNumber class
+// declared below.
+class StaticAtomicSequenceNumber {
+ public:
+ inline int GetNext() {
+ return static_cast<int>(
+ base::subtle::NoBarrier_AtomicIncrement(&seq_, 1) - 1);
+ }
+
+ private:
+ friend class AtomicSequenceNumber;
+
+ inline void Reset() {
+ base::subtle::Release_Store(&seq_, 0);
+ }
+
+ base::subtle::Atomic32 seq_;
+};
+
+// AtomicSequenceNumber that can be stored and used safely (i.e. its fields are
+// always initialized as opposed to StaticAtomicSequenceNumber declared above).
+// Please use StaticAtomicSequenceNumber if you want to declare an atomic
+// sequence number in the global scope.
+class AtomicSequenceNumber {
+ public:
+ AtomicSequenceNumber() {
+ seq_.Reset();
+ }
+
+ inline int GetNext() {
+ return seq_.GetNext();
+ }
+
+ private:
+ StaticAtomicSequenceNumber seq_;
+ DISALLOW_COPY_AND_ASSIGN(AtomicSequenceNumber);
+};
+
+} // namespace base
+
+#endif // BASE_ATOMIC_SEQUENCE_NUM_H_
diff --git a/src/base/atomicops.h b/src/base/atomicops.h
new file mode 100644
index 0000000..230a601
--- /dev/null
+++ b/src/base/atomicops.h
@@ -0,0 +1,169 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// For atomic operations on reference counts, see atomic_refcount.h.
+// For atomic operations on sequence numbers, see atomic_sequence_num.h.
+
+// The routines exported by this module are subtle. If you use them, even if
+// you get the code right, it will depend on careful reasoning about atomicity
+// and memory ordering; it will be less readable, and harder to maintain. If
+// you plan to use these routines, you should have a good reason, such as solid
+// evidence that performance would otherwise suffer, or there being no
+// alternative. You should assume only properties explicitly guaranteed by the
+// specifications in this file. You are almost certainly _not_ writing code
+// just for the x86; if you assume x86 semantics, x86 hardware bugs and
+// implementations on other archtectures will cause your code to break. If you
+// do not know what you are doing, avoid these routines, and use a Mutex.
+//
+// It is incorrect to make direct assignments to/from an atomic variable.
+// You should use one of the Load or Store routines. The NoBarrier
+// versions are provided when no barriers are needed:
+// NoBarrier_Store()
+// NoBarrier_Load()
+// Although there are currently no compiler enforcement, you are encouraged
+// to use these.
+//
+
+#ifndef BASE_ATOMICOPS_H_
+#define BASE_ATOMICOPS_H_
+
+#include "base/basictypes.h"
+#include "build/build_config.h"
+
+#if (defined(OS_WIN) && defined(ARCH_CPU_64_BITS)) || defined(__LB_XB360__) || defined(__LB_XB1__)
+// windows.h #defines this (only on x64). This causes problems because the
+// public API also uses MemoryBarrier at the public name for this fence. So, on
+// X64, undef it, and call its documented
+// (http://msdn.microsoft.com/en-us/library/windows/desktop/ms684208.aspx)
+// implementation directly.
+#undef MemoryBarrier
+#endif
+
+namespace base {
+namespace subtle {
+
+typedef int32 Atomic32;
+#ifdef ARCH_CPU_64_BITS
+// We need to be able to go between Atomic64 and AtomicWord implicitly. This
+// means Atomic64 and AtomicWord should be the same type on 64-bit.
+#if defined(OS_NACL)
+// NaCl's intptr_t is not actually 64-bits on 64-bit!
+// http://code.google.com/p/nativeclient/issues/detail?id=1162
+typedef int64_t Atomic64;
+#else
+typedef intptr_t Atomic64;
+#endif
+#endif
+
+// Use AtomicWord for a machine-sized pointer. It will use the Atomic32 or
+// Atomic64 routines below, depending on your architecture.
+typedef intptr_t AtomicWord;
+
+// Atomically execute:
+// result = *ptr;
+// if (*ptr == old_value)
+// *ptr = new_value;
+// return result;
+//
+// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value".
+// Always return the old value of "*ptr"
+//
+// This routine implies no memory barriers.
+Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value);
+
+// Atomically store new_value into *ptr, returning the previous value held in
+// *ptr. This routine implies no memory barriers.
+Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_value);
+
+// Atomically increment *ptr by "increment". Returns the new value of
+// *ptr with the increment applied. This routine implies no memory barriers.
+Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment);
+
+Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment);
+
+// These following lower-level operations are typically useful only to people
+// implementing higher-level synchronization operations like spinlocks,
+// mutexes, and condition-variables. They combine CompareAndSwap(), a load, or
+// a store with appropriate memory-ordering instructions. "Acquire" operations
+// ensure that no later memory access can be reordered ahead of the operation.
+// "Release" operations ensure that no previous memory access can be reordered
+// after the operation. "Barrier" operations have both "Acquire" and "Release"
+// semantics. A MemoryBarrier() has "Barrier" semantics, but does no memory
+// access.
+Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value);
+Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value);
+
+void MemoryBarrier();
+void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value);
+void Acquire_Store(volatile Atomic32* ptr, Atomic32 value);
+void Release_Store(volatile Atomic32* ptr, Atomic32 value);
+
+Atomic32 NoBarrier_Load(volatile const Atomic32* ptr);
+Atomic32 Acquire_Load(volatile const Atomic32* ptr);
+Atomic32 Release_Load(volatile const Atomic32* ptr);
+
+// 64-bit atomic operations (only available on 64-bit processors).
+#ifdef ARCH_CPU_64_BITS
+Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value);
+Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value);
+Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment);
+Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment);
+
+Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value);
+Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value);
+void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value);
+void Acquire_Store(volatile Atomic64* ptr, Atomic64 value);
+void Release_Store(volatile Atomic64* ptr, Atomic64 value);
+Atomic64 NoBarrier_Load(volatile const Atomic64* ptr);
+Atomic64 Acquire_Load(volatile const Atomic64* ptr);
+Atomic64 Release_Load(volatile const Atomic64* ptr);
+#endif // ARCH_CPU_64_BITS
+
+} // namespace base::subtle
+} // namespace base
+
+// Include our platform specific implementation.
+#if defined(THREAD_SANITIZER)
+#include "base/atomicops_internals_tsan.h"
+#elif defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY)
+#include "base/atomicops_internals_x86_msvc.h"
+#elif defined(OS_MACOSX)
+#include "base/atomicops_internals_mac.h"
+#elif defined(OS_STARBOARD)
+#include "base/atomicops_internals_starboard.h"
+#elif defined(__LB_SHELL__)
+#define SHELL_BEGIN_ATOMICOPS_NAMESPACES namespace base { namespace subtle {
+#define SHELL_END_ATOMICOPS_NAMESPACES } }
+#include "atomicops_internals_shell.h" // from the platform lib
+#elif (defined(COMPILER_GCC) && defined(ARCH_CPU_ARM_FAMILY)) || \
+ defined(OS_NACL)
+#include "base/atomicops_internals_gcc.h"
+#elif defined(COMPILER_GCC) && defined(ARCH_CPU_X86_FAMILY)
+#include "base/atomicops_internals_x86_gcc.h"
+#elif defined(COMPILER_GCC) && defined(ARCH_CPU_MIPS_FAMILY)
+#include "base/atomicops_internals_mips_gcc.h"
+#else
+#error "Atomic operations are not supported on your platform"
+#endif
+
+// On some platforms we need additional declarations to make
+// AtomicWord compatible with our other Atomic* types.
+#if defined(OS_MACOSX) || defined(OS_OPENBSD)
+#include "base/atomicops_internals_atomicword_compat.h"
+#endif
+
+#endif // BASE_ATOMICOPS_H_
diff --git a/src/base/atomicops_internals_atomicword_compat.h b/src/base/atomicops_internals_atomicword_compat.h
new file mode 100644
index 0000000..e02d11d
--- /dev/null
+++ b/src/base/atomicops_internals_atomicword_compat.h
@@ -0,0 +1,100 @@
+// Copyright (c) 2011 The Chromium Authors. 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 an internal atomic implementation, use base/atomicops.h instead.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_
+#define BASE_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_
+
+// AtomicWord is a synonym for intptr_t, and Atomic32 is a synonym for int32,
+// which in turn means int. On some LP32 platforms, intptr_t is an int, but
+// on others, it's a long. When AtomicWord and Atomic32 are based on different
+// fundamental types, their pointers are incompatible.
+//
+// This file defines function overloads to allow both AtomicWord and Atomic32
+// data to be used with this interface.
+//
+// On LP64 platforms, AtomicWord and Atomic64 are both always long,
+// so this problem doesn't occur.
+
+#if !defined(ARCH_CPU_64_BITS)
+
+namespace base {
+namespace subtle {
+
+inline AtomicWord NoBarrier_CompareAndSwap(volatile AtomicWord* ptr,
+ AtomicWord old_value,
+ AtomicWord new_value) {
+ return NoBarrier_CompareAndSwap(
+ reinterpret_cast<volatile Atomic32*>(ptr), old_value, new_value);
+}
+
+inline AtomicWord NoBarrier_AtomicExchange(volatile AtomicWord* ptr,
+ AtomicWord new_value) {
+ return NoBarrier_AtomicExchange(
+ reinterpret_cast<volatile Atomic32*>(ptr), new_value);
+}
+
+inline AtomicWord NoBarrier_AtomicIncrement(volatile AtomicWord* ptr,
+ AtomicWord increment) {
+ return NoBarrier_AtomicIncrement(
+ reinterpret_cast<volatile Atomic32*>(ptr), increment);
+}
+
+inline AtomicWord Barrier_AtomicIncrement(volatile AtomicWord* ptr,
+ AtomicWord increment) {
+ return Barrier_AtomicIncrement(
+ reinterpret_cast<volatile Atomic32*>(ptr), increment);
+}
+
+inline AtomicWord Acquire_CompareAndSwap(volatile AtomicWord* ptr,
+ AtomicWord old_value,
+ AtomicWord new_value) {
+ return base::subtle::Acquire_CompareAndSwap(
+ reinterpret_cast<volatile Atomic32*>(ptr), old_value, new_value);
+}
+
+inline AtomicWord Release_CompareAndSwap(volatile AtomicWord* ptr,
+ AtomicWord old_value,
+ AtomicWord new_value) {
+ return base::subtle::Release_CompareAndSwap(
+ reinterpret_cast<volatile Atomic32*>(ptr), old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile AtomicWord *ptr, AtomicWord value) {
+ NoBarrier_Store(
+ reinterpret_cast<volatile Atomic32*>(ptr), value);
+}
+
+inline void Acquire_Store(volatile AtomicWord* ptr, AtomicWord value) {
+ return base::subtle::Acquire_Store(
+ reinterpret_cast<volatile Atomic32*>(ptr), value);
+}
+
+inline void Release_Store(volatile AtomicWord* ptr, AtomicWord value) {
+ return base::subtle::Release_Store(
+ reinterpret_cast<volatile Atomic32*>(ptr), value);
+}
+
+inline AtomicWord NoBarrier_Load(volatile const AtomicWord *ptr) {
+ return NoBarrier_Load(
+ reinterpret_cast<volatile const Atomic32*>(ptr));
+}
+
+inline AtomicWord Acquire_Load(volatile const AtomicWord* ptr) {
+ return base::subtle::Acquire_Load(
+ reinterpret_cast<volatile const Atomic32*>(ptr));
+}
+
+inline AtomicWord Release_Load(volatile const AtomicWord* ptr) {
+ return base::subtle::Release_Load(
+ reinterpret_cast<volatile const Atomic32*>(ptr));
+}
+
+} // namespace base::subtle
+} // namespace base
+
+#endif // !defined(ARCH_CPU_64_BITS)
+
+#endif // BASE_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_
diff --git a/src/base/atomicops_internals_gcc.h b/src/base/atomicops_internals_gcc.h
new file mode 100644
index 0000000..ed1b2d7
--- /dev/null
+++ b/src/base/atomicops_internals_gcc.h
@@ -0,0 +1,106 @@
+// Copyright (c) 2009 The Chromium Authors. 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 an internal atomic implementation, include base/atomicops.h
+// instead. This file is for platforms that use GCC intrinsics rather than
+// platform-specific assembly code for atomic operations.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_GCC_H_
+#define BASE_ATOMICOPS_INTERNALS_GCC_H_
+
+namespace base {
+namespace subtle {
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 prev_value;
+ do {
+ if (__sync_bool_compare_and_swap(ptr, old_value, new_value))
+ return old_value;
+ prev_value = *ptr;
+ } while (prev_value == old_value);
+ return prev_value;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+ Atomic32 new_value) {
+ Atomic32 old_value;
+ do {
+ old_value = *ptr;
+ } while (!__sync_bool_compare_and_swap(ptr, old_value, new_value));
+ return old_value;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ return Barrier_AtomicIncrement(ptr, increment);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ for (;;) {
+ // Atomic exchange the old value with an incremented one.
+ Atomic32 old_value = *ptr;
+ Atomic32 new_value = old_value + increment;
+ if (__sync_bool_compare_and_swap(ptr, old_value, new_value)) {
+ // The exchange took place as expected.
+ return new_value;
+ }
+ // Otherwise, *ptr changed mid-loop and we need to retry.
+ }
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ // Since NoBarrier_CompareAndSwap uses __sync_bool_compare_and_swap, which
+ // is a full memory barrier, none is needed here or below in Release.
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+}
+
+inline void MemoryBarrier() {
+ __sync_synchronize();
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+ MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+ MemoryBarrier();
+ *ptr = value;
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+ return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+ Atomic32 value = *ptr;
+ MemoryBarrier();
+ return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+ MemoryBarrier();
+ return *ptr;
+}
+
+} // namespace base::subtle
+} // namespace base
+
+#endif // BASE_ATOMICOPS_INTERNALS_GCC_H_
+
diff --git a/src/base/atomicops_internals_mac.h b/src/base/atomicops_internals_mac.h
new file mode 100644
index 0000000..658ed54
--- /dev/null
+++ b/src/base/atomicops_internals_mac.h
@@ -0,0 +1,197 @@
+// Copyright (c) 2012 The Chromium Authors. 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 an internal atomic implementation, use base/atomicops.h instead.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_MAC_H_
+#define BASE_ATOMICOPS_INTERNALS_MAC_H_
+
+#include <libkern/OSAtomic.h>
+
+namespace base {
+namespace subtle {
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 prev_value;
+ do {
+ if (OSAtomicCompareAndSwap32(old_value, new_value,
+ const_cast<Atomic32*>(ptr))) {
+ return old_value;
+ }
+ prev_value = *ptr;
+ } while (prev_value == old_value);
+ return prev_value;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr,
+ Atomic32 new_value) {
+ Atomic32 old_value;
+ do {
+ old_value = *ptr;
+ } while (!OSAtomicCompareAndSwap32(old_value, new_value,
+ const_cast<Atomic32*>(ptr)));
+ return old_value;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32 *ptr,
+ Atomic32 increment) {
+ return OSAtomicAdd32(increment, const_cast<Atomic32*>(ptr));
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32 *ptr,
+ Atomic32 increment) {
+ return OSAtomicAdd32Barrier(increment, const_cast<Atomic32*>(ptr));
+}
+
+inline void MemoryBarrier() {
+ OSMemoryBarrier();
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 prev_value;
+ do {
+ if (OSAtomicCompareAndSwap32Barrier(old_value, new_value,
+ const_cast<Atomic32*>(ptr))) {
+ return old_value;
+ }
+ prev_value = *ptr;
+ } while (prev_value == old_value);
+ return prev_value;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ return Acquire_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic32 *ptr, Atomic32 value) {
+ *ptr = value;
+ MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) {
+ MemoryBarrier();
+ *ptr = value;
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+ return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) {
+ Atomic32 value = *ptr;
+ MemoryBarrier();
+ return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32 *ptr) {
+ MemoryBarrier();
+ return *ptr;
+}
+
+#ifdef __LP64__
+
+// 64-bit implementation on 64-bit platform
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64 *ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 prev_value;
+ do {
+ if (OSAtomicCompareAndSwap64(old_value, new_value,
+ reinterpret_cast<volatile int64_t*>(ptr))) {
+ return old_value;
+ }
+ prev_value = *ptr;
+ } while (prev_value == old_value);
+ return prev_value;
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64 *ptr,
+ Atomic64 new_value) {
+ Atomic64 old_value;
+ do {
+ old_value = *ptr;
+ } while (!OSAtomicCompareAndSwap64(old_value, new_value,
+ reinterpret_cast<volatile int64_t*>(ptr)));
+ return old_value;
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64 *ptr,
+ Atomic64 increment) {
+ return OSAtomicAdd64(increment, reinterpret_cast<volatile int64_t*>(ptr));
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64 *ptr,
+ Atomic64 increment) {
+ return OSAtomicAdd64Barrier(increment,
+ reinterpret_cast<volatile int64_t*>(ptr));
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64 *ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 prev_value;
+ do {
+ if (OSAtomicCompareAndSwap64Barrier(
+ old_value, new_value, reinterpret_cast<volatile int64_t*>(ptr))) {
+ return old_value;
+ }
+ prev_value = *ptr;
+ } while (prev_value == old_value);
+ return prev_value;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64 *ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ // The lib kern interface does not distinguish between
+ // Acquire and Release memory barriers; they are equivalent.
+ return Acquire_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+ *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64 *ptr, Atomic64 value) {
+ *ptr = value;
+ MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic64 *ptr, Atomic64 value) {
+ MemoryBarrier();
+ *ptr = value;
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+ return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) {
+ Atomic64 value = *ptr;
+ MemoryBarrier();
+ return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64 *ptr) {
+ MemoryBarrier();
+ return *ptr;
+}
+
+#endif // defined(__LP64__)
+
+} // namespace base::subtle
+} // namespace base
+
+#endif // BASE_ATOMICOPS_INTERNALS_MAC_H_
diff --git a/src/base/atomicops_internals_mips_gcc.h b/src/base/atomicops_internals_mips_gcc.h
new file mode 100644
index 0000000..505597e
--- /dev/null
+++ b/src/base/atomicops_internals_mips_gcc.h
@@ -0,0 +1,161 @@
+// Copyright (c) 2012 The Chromium Authors. 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 an internal atomic implementation, use base/atomicops.h instead.
+//
+// LinuxKernelCmpxchg and Barrier_AtomicIncrement are from Google Gears.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_MIPS_GCC_H_
+#define BASE_ATOMICOPS_INTERNALS_MIPS_GCC_H_
+
+#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
+
+namespace base {
+namespace subtle {
+
+// Atomically execute:
+// result = *ptr;
+// if (*ptr == old_value)
+// *ptr = new_value;
+// return result;
+//
+// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value".
+// Always return the old value of "*ptr"
+//
+// This routine implies no memory barriers.
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 prev, tmp;
+ __asm__ __volatile__(".set push\n"
+ ".set noreorder\n"
+ "1:\n"
+ "ll %0, %5\n" // prev = *ptr
+ "bne %0, %3, 2f\n" // if (prev != old_value) goto 2
+ "move %2, %4\n" // tmp = new_value
+ "sc %2, %1\n" // *ptr = tmp (with atomic check)
+ "beqz %2, 1b\n" // start again on atomic error
+ "nop\n" // delay slot nop
+ "2:\n"
+ ".set pop\n"
+ : "=&r" (prev), "=m" (*ptr), "=&r" (tmp)
+ : "Ir" (old_value), "r" (new_value), "m" (*ptr)
+ : "memory");
+ return prev;
+}
+
+// Atomically store new_value into *ptr, returning the previous value held in
+// *ptr. This routine implies no memory barriers.
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+ Atomic32 new_value) {
+ Atomic32 temp, old;
+ __asm__ __volatile__(".set push\n"
+ ".set noreorder\n"
+ "1:\n"
+ "ll %1, %2\n" // old = *ptr
+ "move %0, %3\n" // temp = new_value
+ "sc %0, %2\n" // *ptr = temp (with atomic check)
+ "beqz %0, 1b\n" // start again on atomic error
+ "nop\n" // delay slot nop
+ ".set pop\n"
+ : "=&r" (temp), "=&r" (old), "=m" (*ptr)
+ : "r" (new_value), "m" (*ptr)
+ : "memory");
+
+ return old;
+}
+
+// Atomically increment *ptr by "increment". Returns the new value of
+// *ptr with the increment applied. This routine implies no memory barriers.
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ Atomic32 temp, temp2;
+
+ __asm__ __volatile__(".set push\n"
+ ".set noreorder\n"
+ "1:\n"
+ "ll %0, %2\n" // temp = *ptr
+ "addu %1, %0, %3\n" // temp2 = temp + increment
+ "sc %1, %2\n" // *ptr = temp2 (with atomic check)
+ "beqz %1, 1b\n" // start again on atomic error
+ "addu %1, %0, %3\n" // temp2 = temp + increment
+ ".set pop\n"
+ : "=&r" (temp), "=&r" (temp2), "=m" (*ptr)
+ : "Ir" (increment), "m" (*ptr)
+ : "memory");
+ // temp2 now holds the final value.
+ return temp2;
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ ATOMICOPS_COMPILER_BARRIER();
+ Atomic32 res = NoBarrier_AtomicIncrement(ptr, increment);
+ ATOMICOPS_COMPILER_BARRIER();
+ return res;
+}
+
+// "Acquire" operations
+// ensure that no later memory access can be reordered ahead of the operation.
+// "Release" operations ensure that no previous memory access can be reordered
+// after the operation. "Barrier" operations have both "Acquire" and "Release"
+// semantics. A MemoryBarrier() has "Barrier" semantics, but does no memory
+// access.
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ ATOMICOPS_COMPILER_BARRIER();
+ Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+ ATOMICOPS_COMPILER_BARRIER();
+ return res;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ ATOMICOPS_COMPILER_BARRIER();
+ Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+ ATOMICOPS_COMPILER_BARRIER();
+ return res;
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+}
+
+inline void MemoryBarrier() {
+ __asm__ __volatile__("sync" : : : "memory");
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+ MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+ MemoryBarrier();
+ *ptr = value;
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+ return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+ Atomic32 value = *ptr;
+ MemoryBarrier();
+ return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+ MemoryBarrier();
+ return *ptr;
+}
+
+} // namespace base::subtle
+} // namespace base
+
+#undef ATOMICOPS_COMPILER_BARRIER
+
+#endif // BASE_ATOMICOPS_INTERNALS_MIPS_GCC_H_
diff --git a/src/base/atomicops_internals_starboard.h b/src/base/atomicops_internals_starboard.h
new file mode 100644
index 0000000..cb1c759
--- /dev/null
+++ b/src/base/atomicops_internals_starboard.h
@@ -0,0 +1,151 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This file is an internal atomic implementation, use base/atomicops.h instead.
+
+// This is the Starboard implementation, which defers all specific
+// implementation decisions for atomic operations to the Starboard port.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_STARBOARD_H_
+#define BASE_ATOMICOPS_INTERNALS_STARBOARD_H_
+
+#include "starboard/atomic.h"
+
+namespace base {
+namespace subtle {
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ return SbAtomicNoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr,
+ Atomic32 new_value) {
+ return SbAtomicNoBarrier_Exchange(ptr, new_value);
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32 *ptr,
+ Atomic32 increment) {
+ return SbAtomicNoBarrier_Increment(ptr, increment);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32 *ptr,
+ Atomic32 increment) {
+ return SbAtomicBarrier_Increment(ptr, increment);
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ return SbAtomicAcquire_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ return SbAtomicRelease_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32 *ptr, Atomic32 value) {
+ SbAtomicNoBarrier_Store(ptr, value);
+}
+
+inline void MemoryBarrier() {
+ SbAtomicMemoryBarrier();
+}
+
+inline void Acquire_Store(volatile Atomic32 *ptr, Atomic32 value) {
+ SbAtomicAcquire_Store(ptr, value);
+}
+
+inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) {
+ SbAtomicRelease_Store(ptr, value);
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32 *ptr) {
+ return SbAtomicNoBarrier_Load(ptr);
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) {
+ return SbAtomicAcquire_Load(ptr);
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32 *ptr) {
+ return SbAtomicRelease_Load(ptr);
+}
+
+#if SB_IS(64_BIT)
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64 *ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ return SbAtomicNoBarrier_CompareAndSwap64(ptr, old_value, new_value);
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64 *ptr,
+ Atomic64 new_value) {
+ return SbAtomicNoBarrier_Exchange64(ptr, new_value);
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64 *ptr,
+ Atomic64 increment) {
+ return SbAtomicNoBarrier_Increment64(ptr, increment);
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64 *ptr,
+ Atomic64 increment) {
+ return SbAtomicBarrier_Increment64(ptr, increment);
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64 *ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ return SbAtomicAcquire_CompareAndSwap64(ptr, old_value, new_value);
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64 *ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ return SbAtomicRelease_CompareAndSwap64(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic64 *ptr, Atomic64 value) {
+ SbAtomicNoBarrier_Store64(ptr, value);
+}
+
+inline void Acquire_Store(volatile Atomic64 *ptr, Atomic64 value) {
+ SbAtomicAcquire_Store64(ptr, value);
+}
+
+inline void Release_Store(volatile Atomic64 *ptr, Atomic64 value) {
+ SbAtomicRelease_Store64(ptr, value);
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64 *ptr) {
+ return SbAtomicNoBarrier_Load64(ptr);
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) {
+ return SbAtomicAcquire_Load64(ptr);
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64 *ptr) {
+ return SbAtomicRelease_Load64(ptr);
+}
+#endif // SB_IS(64_BIT)
+
+} // namespace base::subtle
+} // namespace base
+
+#endif // BASE_ATOMICOPS_INTERNALS_STARBOARD_H_
diff --git a/src/base/atomicops_internals_tsan.h b/src/base/atomicops_internals_tsan.h
new file mode 100644
index 0000000..44d6400
--- /dev/null
+++ b/src/base/atomicops_internals_tsan.h
@@ -0,0 +1,378 @@
+// Copyright (c) 2012 The Chromium Authors. 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 an internal atomic implementation for compiler-based
+// ThreadSanitizer. Use base/atomicops.h instead.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_TSAN_H_
+#define BASE_ATOMICOPS_INTERNALS_TSAN_H_
+
+#include "base/base_export.h"
+
+// This struct is not part of the public API of this module; clients may not
+// use it. (However, it's exported via BASE_EXPORT because clients implicitly
+// do use it at link time by inlining these functions.)
+// Features of this x86. Values may not be correct before main() is run,
+// but are set conservatively.
+struct AtomicOps_x86CPUFeatureStruct {
+ bool has_amd_lock_mb_bug; // Processor has AMD memory-barrier bug; do lfence
+ // after acquire compare-and-swap.
+ bool has_sse2; // Processor has SSE2.
+};
+BASE_EXPORT extern struct AtomicOps_x86CPUFeatureStruct
+ AtomicOps_Internalx86CPUFeatures;
+
+#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
+
+namespace base {
+namespace subtle {
+
+#ifndef TSAN_INTERFACE_ATOMIC_H
+#define TSAN_INTERFACE_ATOMIC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef char __tsan_atomic8;
+typedef short __tsan_atomic16; // NOLINT
+typedef int __tsan_atomic32;
+typedef long __tsan_atomic64; // NOLINT
+
+#if defined(__SIZEOF_INT128__) \
+ || (__clang_major__ * 100 + __clang_minor__ >= 302)
+typedef __int128 __tsan_atomic128;
+#define __TSAN_HAS_INT128 1
+#else
+typedef char __tsan_atomic128;
+#define __TSAN_HAS_INT128 0
+#endif
+
+typedef enum {
+ __tsan_memory_order_relaxed,
+ __tsan_memory_order_consume,
+ __tsan_memory_order_acquire,
+ __tsan_memory_order_release,
+ __tsan_memory_order_acq_rel,
+ __tsan_memory_order_seq_cst,
+} __tsan_memory_order;
+
+__tsan_atomic8 __tsan_atomic8_load(const volatile __tsan_atomic8 *a,
+ __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_load(const volatile __tsan_atomic16 *a,
+ __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_load(const volatile __tsan_atomic32 *a,
+ __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_load(const volatile __tsan_atomic64 *a,
+ __tsan_memory_order mo);
+__tsan_atomic128 __tsan_atomic128_load(const volatile __tsan_atomic128 *a,
+ __tsan_memory_order mo);
+
+void __tsan_atomic8_store(volatile __tsan_atomic8 *a, __tsan_atomic8 v,
+ __tsan_memory_order mo);
+void __tsan_atomic16_store(volatile __tsan_atomic16 *a, __tsan_atomic16 v,
+ __tsan_memory_order mo);
+void __tsan_atomic32_store(volatile __tsan_atomic32 *a, __tsan_atomic32 v,
+ __tsan_memory_order mo);
+void __tsan_atomic64_store(volatile __tsan_atomic64 *a, __tsan_atomic64 v,
+ __tsan_memory_order mo);
+void __tsan_atomic128_store(volatile __tsan_atomic128 *a, __tsan_atomic128 v,
+ __tsan_memory_order mo);
+
+__tsan_atomic8 __tsan_atomic8_exchange(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_exchange(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_exchange(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_exchange(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 v, __tsan_memory_order mo);
+__tsan_atomic128 __tsan_atomic128_exchange(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 v, __tsan_memory_order mo);
+
+__tsan_atomic8 __tsan_atomic8_fetch_add(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_add(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_add(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_add(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 v, __tsan_memory_order mo);
+__tsan_atomic128 __tsan_atomic128_fetch_add(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 v, __tsan_memory_order mo);
+
+__tsan_atomic8 __tsan_atomic8_fetch_and(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_and(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_and(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_and(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 v, __tsan_memory_order mo);
+__tsan_atomic128 __tsan_atomic128_fetch_and(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 v, __tsan_memory_order mo);
+
+__tsan_atomic8 __tsan_atomic8_fetch_or(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_or(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_or(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_or(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 v, __tsan_memory_order mo);
+__tsan_atomic128 __tsan_atomic128_fetch_or(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 v, __tsan_memory_order mo);
+
+__tsan_atomic8 __tsan_atomic8_fetch_xor(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_xor(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_xor(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_xor(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 v, __tsan_memory_order mo);
+__tsan_atomic128 __tsan_atomic128_fetch_xor(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 v, __tsan_memory_order mo);
+
+__tsan_atomic8 __tsan_atomic8_fetch_nand(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_nand(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_nand(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_nand(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 v, __tsan_memory_order mo);
+__tsan_atomic128 __tsan_atomic128_fetch_nand(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 v, __tsan_memory_order mo);
+
+int __tsan_atomic8_compare_exchange_weak(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+int __tsan_atomic16_compare_exchange_weak(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+int __tsan_atomic32_compare_exchange_weak(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+int __tsan_atomic64_compare_exchange_weak(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+int __tsan_atomic128_compare_exchange_weak(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 *c, __tsan_atomic128 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+
+int __tsan_atomic8_compare_exchange_strong(volatile __tsan_atomic8 *a,
+ __tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+int __tsan_atomic16_compare_exchange_strong(volatile __tsan_atomic16 *a,
+ __tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+int __tsan_atomic32_compare_exchange_strong(volatile __tsan_atomic32 *a,
+ __tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+int __tsan_atomic64_compare_exchange_strong(volatile __tsan_atomic64 *a,
+ __tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+int __tsan_atomic128_compare_exchange_strong(volatile __tsan_atomic128 *a,
+ __tsan_atomic128 *c, __tsan_atomic128 v, __tsan_memory_order mo,
+ __tsan_memory_order fail_mo);
+
+__tsan_atomic8 __tsan_atomic8_compare_exchange_val(
+ volatile __tsan_atomic8 *a, __tsan_atomic8 c, __tsan_atomic8 v,
+ __tsan_memory_order mo, __tsan_memory_order fail_mo);
+__tsan_atomic16 __tsan_atomic16_compare_exchange_val(
+ volatile __tsan_atomic16 *a, __tsan_atomic16 c, __tsan_atomic16 v,
+ __tsan_memory_order mo, __tsan_memory_order fail_mo);
+__tsan_atomic32 __tsan_atomic32_compare_exchange_val(
+ volatile __tsan_atomic32 *a, __tsan_atomic32 c, __tsan_atomic32 v,
+ __tsan_memory_order mo, __tsan_memory_order fail_mo);
+__tsan_atomic64 __tsan_atomic64_compare_exchange_val(
+ volatile __tsan_atomic64 *a, __tsan_atomic64 c, __tsan_atomic64 v,
+ __tsan_memory_order mo, __tsan_memory_order fail_mo);
+__tsan_atomic128 __tsan_atomic128_compare_exchange_val(
+ volatile __tsan_atomic128 *a, __tsan_atomic128 c, __tsan_atomic128 v,
+ __tsan_memory_order mo, __tsan_memory_order fail_mo);
+
+void __tsan_atomic_thread_fence(__tsan_memory_order mo);
+void __tsan_atomic_signal_fence(__tsan_memory_order mo);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // #ifndef TSAN_INTERFACE_ATOMIC_H
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 cmp = old_value;
+ __tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
+ __tsan_memory_order_relaxed, __tsan_memory_order_relaxed);
+ return cmp;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr,
+ Atomic32 new_value) {
+ return __tsan_atomic32_exchange(ptr, new_value,
+ __tsan_memory_order_relaxed);
+}
+
+inline Atomic32 Acquire_AtomicExchange(volatile Atomic32 *ptr,
+ Atomic32 new_value) {
+ return __tsan_atomic32_exchange(ptr, new_value,
+ __tsan_memory_order_acquire);
+}
+
+inline Atomic32 Release_AtomicExchange(volatile Atomic32 *ptr,
+ Atomic32 new_value) {
+ return __tsan_atomic32_exchange(ptr, new_value,
+ __tsan_memory_order_release);
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32 *ptr,
+ Atomic32 increment) {
+ return increment + __tsan_atomic32_fetch_add(ptr, increment,
+ __tsan_memory_order_relaxed);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32 *ptr,
+ Atomic32 increment) {
+ return increment + __tsan_atomic32_fetch_add(ptr, increment,
+ __tsan_memory_order_acq_rel);
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 cmp = old_value;
+ __tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
+ __tsan_memory_order_acquire, __tsan_memory_order_acquire);
+ return cmp;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 cmp = old_value;
+ __tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
+ __tsan_memory_order_release, __tsan_memory_order_relaxed);
+ return cmp;
+}
+
+inline void NoBarrier_Store(volatile Atomic32 *ptr, Atomic32 value) {
+ __tsan_atomic32_store(ptr, value, __tsan_memory_order_relaxed);
+}
+
+inline void Acquire_Store(volatile Atomic32 *ptr, Atomic32 value) {
+ __tsan_atomic32_store(ptr, value, __tsan_memory_order_relaxed);
+ __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
+}
+
+inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) {
+ __tsan_atomic32_store(ptr, value, __tsan_memory_order_release);
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32 *ptr) {
+ return __tsan_atomic32_load(ptr, __tsan_memory_order_relaxed);
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) {
+ return __tsan_atomic32_load(ptr, __tsan_memory_order_acquire);
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32 *ptr) {
+ __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
+ return __tsan_atomic32_load(ptr, __tsan_memory_order_relaxed);
+}
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64 *ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 cmp = old_value;
+ __tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
+ __tsan_memory_order_relaxed, __tsan_memory_order_relaxed);
+ return cmp;
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64 *ptr,
+ Atomic64 new_value) {
+ return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_relaxed);
+}
+
+inline Atomic64 Acquire_AtomicExchange(volatile Atomic64 *ptr,
+ Atomic64 new_value) {
+ return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_acquire);
+}
+
+inline Atomic64 Release_AtomicExchange(volatile Atomic64 *ptr,
+ Atomic64 new_value) {
+ return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_release);
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64 *ptr,
+ Atomic64 increment) {
+ return increment + __tsan_atomic64_fetch_add(ptr, increment,
+ __tsan_memory_order_relaxed);
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64 *ptr,
+ Atomic64 increment) {
+ return increment + __tsan_atomic64_fetch_add(ptr, increment,
+ __tsan_memory_order_acq_rel);
+}
+
+inline void NoBarrier_Store(volatile Atomic64 *ptr, Atomic64 value) {
+ __tsan_atomic64_store(ptr, value, __tsan_memory_order_relaxed);
+}
+
+inline void Acquire_Store(volatile Atomic64 *ptr, Atomic64 value) {
+ __tsan_atomic64_store(ptr, value, __tsan_memory_order_relaxed);
+ __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
+}
+
+inline void Release_Store(volatile Atomic64 *ptr, Atomic64 value) {
+ __tsan_atomic64_store(ptr, value, __tsan_memory_order_release);
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64 *ptr) {
+ return __tsan_atomic64_load(ptr, __tsan_memory_order_relaxed);
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) {
+ return __tsan_atomic64_load(ptr, __tsan_memory_order_acquire);
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64 *ptr) {
+ __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
+ return __tsan_atomic64_load(ptr, __tsan_memory_order_relaxed);
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64 *ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 cmp = old_value;
+ __tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
+ __tsan_memory_order_acquire, __tsan_memory_order_acquire);
+ return cmp;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64 *ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 cmp = old_value;
+ __tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
+ __tsan_memory_order_release, __tsan_memory_order_relaxed);
+ return cmp;
+}
+
+inline void MemoryBarrier() {
+ __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
+}
+
+} // namespace base::subtle
+} // namespace base
+
+#undef ATOMICOPS_COMPILER_BARRIER
+
+#endif // BASE_ATOMICOPS_INTERNALS_TSAN_H_
diff --git a/src/base/atomicops_internals_x86_gcc.cc b/src/base/atomicops_internals_x86_gcc.cc
new file mode 100644
index 0000000..933ca51
--- /dev/null
+++ b/src/base/atomicops_internals_x86_gcc.cc
@@ -0,0 +1,104 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This module gets enough CPU information to optimize the
+// atomicops module on x86.
+
+#include <string.h>
+
+#include "base/atomicops.h"
+#include "base/basictypes.h"
+
+// This file only makes sense with atomicops_internals_x86_gcc.h -- it
+// depends on structs that are defined in that file. If atomicops.h
+// doesn't sub-include that file, then we aren't needed, and shouldn't
+// try to do anything.
+#ifdef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
+
+// Inline cpuid instruction. In PIC compilations, %ebx contains the address
+// of the global offset table. To avoid breaking such executables, this code
+// must preserve that register's value across cpuid instructions.
+#if defined(__i386__)
+#define cpuid(a, b, c, d, inp) \
+ asm ("mov %%ebx, %%edi\n" \
+ "cpuid\n" \
+ "xchg %%edi, %%ebx\n" \
+ : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp))
+#elif defined (__x86_64__)
+#define cpuid(a, b, c, d, inp) \
+ asm ("mov %%rbx, %%rdi\n" \
+ "cpuid\n" \
+ "xchg %%rdi, %%rbx\n" \
+ : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp))
+#endif
+
+#if defined(cpuid) // initialize the struct only on x86
+
+// Set the flags so that code will run correctly and conservatively, so even
+// if we haven't been initialized yet, we're probably single threaded, and our
+// default values should hopefully be pretty safe.
+struct AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures = {
+ false, // bug can't exist before process spawns multiple threads
+ false, // no SSE2
+};
+
+// Initialize the AtomicOps_Internalx86CPUFeatures struct.
+static void AtomicOps_Internalx86CPUFeaturesInit() {
+ uint32 eax;
+ uint32 ebx;
+ uint32 ecx;
+ uint32 edx;
+
+ // Get vendor string (issue CPUID with eax = 0)
+ cpuid(eax, ebx, ecx, edx, 0);
+ char vendor[13];
+ memcpy(vendor, &ebx, 4);
+ memcpy(vendor + 4, &edx, 4);
+ memcpy(vendor + 8, &ecx, 4);
+ vendor[12] = 0;
+
+ // get feature flags in ecx/edx, and family/model in eax
+ cpuid(eax, ebx, ecx, edx, 1);
+
+ int family = (eax >> 8) & 0xf; // family and model fields
+ int model = (eax >> 4) & 0xf;
+ if (family == 0xf) { // use extended family and model fields
+ family += (eax >> 20) & 0xff;
+ model += ((eax >> 16) & 0xf) << 4;
+ }
+
+ // Opteron Rev E has a bug in which on very rare occasions a locked
+ // instruction doesn't act as a read-acquire barrier if followed by a
+ // non-locked read-modify-write instruction. Rev F has this bug in
+ // pre-release versions, but not in versions released to customers,
+ // so we test only for Rev E, which is family 15, model 32..63 inclusive.
+ if (strcmp(vendor, "AuthenticAMD") == 0 && // AMD
+ family == 15 &&
+ 32 <= model && model <= 63) {
+ AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = true;
+ } else {
+ AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = false;
+ }
+
+ // edx bit 26 is SSE2 which we use to tell use whether we can use mfence
+ AtomicOps_Internalx86CPUFeatures.has_sse2 = ((edx >> 26) & 1);
+}
+
+namespace {
+
+class AtomicOpsx86Initializer {
+ public:
+ AtomicOpsx86Initializer() {
+ AtomicOps_Internalx86CPUFeaturesInit();
+ }
+};
+
+// A global to get use initialized on startup via static initialization :/
+AtomicOpsx86Initializer g_initer;
+
+} // namespace
+
+#endif // if x86
+
+#endif // ifdef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
diff --git a/src/base/atomicops_internals_x86_gcc.h b/src/base/atomicops_internals_x86_gcc.h
new file mode 100644
index 0000000..ac02b17
--- /dev/null
+++ b/src/base/atomicops_internals_x86_gcc.h
@@ -0,0 +1,269 @@
+// Copyright (c) 2011 The Chromium Authors. 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 an internal atomic implementation, use base/atomicops.h instead.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
+#define BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
+
+#include "base/base_export.h"
+
+// This struct is not part of the public API of this module; clients may not
+// use it. (However, it's exported via BASE_EXPORT because clients implicitly
+// do use it at link time by inlining these functions.)
+// Features of this x86. Values may not be correct before main() is run,
+// but are set conservatively.
+struct AtomicOps_x86CPUFeatureStruct {
+ bool has_amd_lock_mb_bug; // Processor has AMD memory-barrier bug; do lfence
+ // after acquire compare-and-swap.
+ bool has_sse2; // Processor has SSE2.
+};
+BASE_EXPORT extern struct AtomicOps_x86CPUFeatureStruct
+ AtomicOps_Internalx86CPUFeatures;
+
+#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
+
+namespace base {
+namespace subtle {
+
+// 32-bit low-level operations on any platform.
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 prev;
+ __asm__ __volatile__("lock; cmpxchgl %1,%2"
+ : "=a" (prev)
+ : "q" (new_value), "m" (*ptr), "0" (old_value)
+ : "memory");
+ return prev;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+ Atomic32 new_value) {
+ __asm__ __volatile__("xchgl %1,%0" // The lock prefix is implicit for xchg.
+ : "=r" (new_value)
+ : "m" (*ptr), "0" (new_value)
+ : "memory");
+ return new_value; // Now it's the previous value.
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ Atomic32 temp = increment;
+ __asm__ __volatile__("lock; xaddl %0,%1"
+ : "+r" (temp), "+m" (*ptr)
+ : : "memory");
+ // temp now holds the old value of *ptr
+ return temp + increment;
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ Atomic32 temp = increment;
+ __asm__ __volatile__("lock; xaddl %0,%1"
+ : "+r" (temp), "+m" (*ptr)
+ : : "memory");
+ // temp now holds the old value of *ptr
+ if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
+ __asm__ __volatile__("lfence" : : : "memory");
+ }
+ return temp + increment;
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+ if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
+ __asm__ __volatile__("lfence" : : : "memory");
+ }
+ return x;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+}
+
+#if defined(__x86_64__)
+
+// 64-bit implementations of memory barrier can be simpler, because it
+// "mfence" is guaranteed to exist.
+inline void MemoryBarrier() {
+ __asm__ __volatile__("mfence" : : : "memory");
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+ MemoryBarrier();
+}
+
+#else
+
+inline void MemoryBarrier() {
+ if (AtomicOps_Internalx86CPUFeatures.has_sse2) {
+ __asm__ __volatile__("mfence" : : : "memory");
+ } else { // mfence is faster but not present on PIII
+ Atomic32 x = 0;
+ NoBarrier_AtomicExchange(&x, 0); // acts as a barrier on PIII
+ }
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+ if (AtomicOps_Internalx86CPUFeatures.has_sse2) {
+ *ptr = value;
+ __asm__ __volatile__("mfence" : : : "memory");
+ } else {
+ NoBarrier_AtomicExchange(ptr, value);
+ // acts as a barrier on PIII
+ }
+}
+#endif
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+ ATOMICOPS_COMPILER_BARRIER();
+ *ptr = value; // An x86 store acts as a release barrier.
+ // See comments in Atomic64 version of Release_Store(), below.
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+ return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+ Atomic32 value = *ptr; // An x86 load acts as a acquire barrier.
+ // See comments in Atomic64 version of Release_Store(), below.
+ ATOMICOPS_COMPILER_BARRIER();
+ return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+ MemoryBarrier();
+ return *ptr;
+}
+
+#if defined(__x86_64__)
+
+// 64-bit low-level operations on 64-bit platform.
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 prev;
+ __asm__ __volatile__("lock; cmpxchgq %1,%2"
+ : "=a" (prev)
+ : "q" (new_value), "m" (*ptr), "0" (old_value)
+ : "memory");
+ return prev;
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+ Atomic64 new_value) {
+ __asm__ __volatile__("xchgq %1,%0" // The lock prefix is implicit for xchg.
+ : "=r" (new_value)
+ : "m" (*ptr), "0" (new_value)
+ : "memory");
+ return new_value; // Now it's the previous value.
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ Atomic64 temp = increment;
+ __asm__ __volatile__("lock; xaddq %0,%1"
+ : "+r" (temp), "+m" (*ptr)
+ : : "memory");
+ // temp now contains the previous value of *ptr
+ return temp + increment;
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ Atomic64 temp = increment;
+ __asm__ __volatile__("lock; xaddq %0,%1"
+ : "+r" (temp), "+m" (*ptr)
+ : : "memory");
+ // temp now contains the previous value of *ptr
+ if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
+ __asm__ __volatile__("lfence" : : : "memory");
+ }
+ return temp + increment;
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+ *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+ *ptr = value;
+ MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+ ATOMICOPS_COMPILER_BARRIER();
+
+ *ptr = value; // An x86 store acts as a release barrier
+ // for current AMD/Intel chips as of Jan 2008.
+ // See also Acquire_Load(), below.
+
+ // When new chips come out, check:
+ // IA-32 Intel Architecture Software Developer's Manual, Volume 3:
+ // System Programming Guide, Chatper 7: Multiple-processor management,
+ // Section 7.2, Memory Ordering.
+ // Last seen at:
+ // http://developer.intel.com/design/pentium4/manuals/index_new.htm
+ //
+ // x86 stores/loads fail to act as barriers for a few instructions (clflush
+ // maskmovdqu maskmovq movntdq movnti movntpd movntps movntq) but these are
+ // not generated by the compiler, and are rare. Users of these instructions
+ // need to know about cache behaviour in any case since all of these involve
+ // either flushing cache lines or non-temporal cache hints.
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+ return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+ Atomic64 value = *ptr; // An x86 load acts as a acquire barrier,
+ // for current AMD/Intel chips as of Jan 2008.
+ // See also Release_Store(), above.
+ ATOMICOPS_COMPILER_BARRIER();
+ return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+ MemoryBarrier();
+ return *ptr;
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+ if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
+ __asm__ __volatile__("lfence" : : : "memory");
+ }
+ return x;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+#endif // defined(__x86_64__)
+
+} // namespace base::subtle
+} // namespace base
+
+#undef ATOMICOPS_COMPILER_BARRIER
+
+#endif // BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
diff --git a/src/base/atomicops_internals_x86_msvc.h b/src/base/atomicops_internals_x86_msvc.h
new file mode 100644
index 0000000..2f428b6
--- /dev/null
+++ b/src/base/atomicops_internals_x86_msvc.h
@@ -0,0 +1,224 @@
+// Copyright (c) 2006-2008 The Chromium Authors. 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 an internal atomic implementation, use base/atomicops.h instead.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
+#define BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
+
+#if defined(__LB_XB1__) && !defined(WIN32)
+# include <intrin.h>
+// These are normally defined by windows.h:
+typedef long LONG;
+typedef long long LONGLONG;
+typedef void* PVOID;
+void __faststorefence(void);
+#pragma intrinsic(__faststorefence)
+inline void MemoryBarrier() {
+ __faststorefence();
+}
+#define InterlockedCompareExchange _InterlockedCompareExchange
+#define InterlockedCompareExchangePointer _InterlockedCompareExchangePointer
+#define InterlockedExchangePointer _InterlockedExchangePointer
+#define InterlockedExchange _InterlockedExchange
+#define InterlockedExchangeAdd _InterlockedExchangeAdd
+#define InterlockedExchangeAdd64 _InterlockedExchangeAdd64
+
+#else
+# include <windows.h>
+
+#if defined(ARCH_CPU_64_BITS) || defined(__LB_XB360__)
+// windows.h #defines this (only on x64). This causes problems because the
+// public API also uses MemoryBarrier at the public name for this fence. So, on
+// X64, undef it, and call its documented
+// (http://msdn.microsoft.com/en-us/library/windows/desktop/ms684208.aspx)
+// implementation directly.
+#undef MemoryBarrier
+#endif
+
+#endif
+
+namespace base {
+namespace subtle {
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ LONG result = InterlockedCompareExchange(
+ reinterpret_cast<volatile LONG*>(ptr),
+ static_cast<LONG>(new_value),
+ static_cast<LONG>(old_value));
+ return static_cast<Atomic32>(result);
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+ Atomic32 new_value) {
+ LONG result = InterlockedExchange(
+ reinterpret_cast<volatile LONG*>(ptr),
+ static_cast<LONG>(new_value));
+ return static_cast<Atomic32>(result);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ return InterlockedExchangeAdd(
+ reinterpret_cast<volatile LONG*>(ptr),
+ static_cast<LONG>(increment)) + increment;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ return Barrier_AtomicIncrement(ptr, increment);
+}
+
+#if !(defined(_MSC_VER) && _MSC_VER >= 1400)
+#error "We require at least vs2005 for MemoryBarrier"
+#endif
+inline void MemoryBarrier() {
+#if defined(ARCH_CPU_64_BITS) || defined(__LB_XB360__)
+ // See #undef and note at the top of this file.
+ __faststorefence();
+#else
+ // We use MemoryBarrier from WinNT.h
+ ::MemoryBarrier();
+#endif
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+ NoBarrier_AtomicExchange(ptr, value);
+ // acts as a barrier in this implementation
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value; // works w/o barrier for current Intel chips as of June 2005
+ // See comments in Atomic64 version of Release_Store() below.
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+ return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+ Atomic32 value = *ptr;
+ return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+ MemoryBarrier();
+ return *ptr;
+}
+
+#if defined(_WIN64)
+
+// 64-bit low-level operations on 64-bit platform.
+
+COMPILE_ASSERT(sizeof(Atomic64) == sizeof(PVOID), atomic_word_is_atomic);
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ PVOID result = InterlockedCompareExchangePointer(
+ reinterpret_cast<volatile PVOID*>(ptr),
+ reinterpret_cast<PVOID>(new_value), reinterpret_cast<PVOID>(old_value));
+ return reinterpret_cast<Atomic64>(result);
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+ Atomic64 new_value) {
+ PVOID result = InterlockedExchangePointer(
+ reinterpret_cast<volatile PVOID*>(ptr),
+ reinterpret_cast<PVOID>(new_value));
+ return reinterpret_cast<Atomic64>(result);
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ return InterlockedExchangeAdd64(
+ reinterpret_cast<volatile LONGLONG*>(ptr),
+ static_cast<LONGLONG>(increment)) + increment;
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ return Barrier_AtomicIncrement(ptr, increment);
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+ *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+ NoBarrier_AtomicExchange(ptr, value);
+ // acts as a barrier in this implementation
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+ *ptr = value; // works w/o barrier for current Intel chips as of June 2005
+
+ // When new chips come out, check:
+ // IA-32 Intel Architecture Software Developer's Manual, Volume 3:
+ // System Programming Guide, Chatper 7: Multiple-processor management,
+ // Section 7.2, Memory Ordering.
+ // Last seen at:
+ // http://developer.intel.com/design/pentium4/manuals/index_new.htm
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+ return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+ Atomic64 value = *ptr;
+ return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+ MemoryBarrier();
+ return *ptr;
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+
+#endif // defined(_WIN64)
+
+} // namespace base::subtle
+} // namespace base
+
+#if defined(__LB_XB1__)
+#undef InterlockedCompareExchange
+#undef InterlockedCompareExchangePointer
+#undef InterlockedExchangePointer
+#undef InterlockedExchange
+#undef InterlockedExchangeAdd
+#undef InterlockedExchangeAdd64
+#endif
+
+#endif // BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
diff --git a/src/base/atomicops_unittest.cc b/src/base/atomicops_unittest.cc
new file mode 100644
index 0000000..d73a098
--- /dev/null
+++ b/src/base/atomicops_unittest.cc
@@ -0,0 +1,241 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/atomicops.h"
+
+#include <string.h>
+
+#include "base/port.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+template <class AtomicType>
+static void TestAtomicIncrement() {
+ // For now, we just test single threaded execution
+
+ // use a guard value to make sure the NoBarrier_AtomicIncrement doesn't go
+ // outside the expected address bounds. This is in particular to
+ // test that some future change to the asm code doesn't cause the
+ // 32-bit NoBarrier_AtomicIncrement doesn't do the wrong thing on 64-bit
+ // machines.
+ struct {
+ AtomicType prev_word;
+ AtomicType count;
+ AtomicType next_word;
+ } s;
+
+ AtomicType prev_word_value, next_word_value;
+ memset(&prev_word_value, 0xFF, sizeof(AtomicType));
+ memset(&next_word_value, 0xEE, sizeof(AtomicType));
+
+ s.prev_word = prev_word_value;
+ s.count = 0;
+ s.next_word = next_word_value;
+
+ EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 1), 1);
+ EXPECT_EQ(s.count, 1);
+ EXPECT_EQ(s.prev_word, prev_word_value);
+ EXPECT_EQ(s.next_word, next_word_value);
+
+ EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 2), 3);
+ EXPECT_EQ(s.count, 3);
+ EXPECT_EQ(s.prev_word, prev_word_value);
+ EXPECT_EQ(s.next_word, next_word_value);
+
+ EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 3), 6);
+ EXPECT_EQ(s.count, 6);
+ EXPECT_EQ(s.prev_word, prev_word_value);
+ EXPECT_EQ(s.next_word, next_word_value);
+
+ EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -3), 3);
+ EXPECT_EQ(s.count, 3);
+ EXPECT_EQ(s.prev_word, prev_word_value);
+ EXPECT_EQ(s.next_word, next_word_value);
+
+ EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -2), 1);
+ EXPECT_EQ(s.count, 1);
+ EXPECT_EQ(s.prev_word, prev_word_value);
+ EXPECT_EQ(s.next_word, next_word_value);
+
+ EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), 0);
+ EXPECT_EQ(s.count, 0);
+ EXPECT_EQ(s.prev_word, prev_word_value);
+ EXPECT_EQ(s.next_word, next_word_value);
+
+ EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), -1);
+ EXPECT_EQ(s.count, -1);
+ EXPECT_EQ(s.prev_word, prev_word_value);
+ EXPECT_EQ(s.next_word, next_word_value);
+
+ EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -4), -5);
+ EXPECT_EQ(s.count, -5);
+ EXPECT_EQ(s.prev_word, prev_word_value);
+ EXPECT_EQ(s.next_word, next_word_value);
+
+ EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 5), 0);
+ EXPECT_EQ(s.count, 0);
+ EXPECT_EQ(s.prev_word, prev_word_value);
+ EXPECT_EQ(s.next_word, next_word_value);
+}
+
+
+#define NUM_BITS(T) (sizeof(T) * 8)
+
+
+template <class AtomicType>
+static void TestCompareAndSwap() {
+ AtomicType value = 0;
+ AtomicType prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 1);
+ EXPECT_EQ(1, value);
+ EXPECT_EQ(0, prev);
+
+ // Use test value that has non-zero bits in both halves, more for testing
+ // 64-bit implementation on 32-bit platforms.
+ const AtomicType k_test_val = (GG_ULONGLONG(1) <<
+ (NUM_BITS(AtomicType) - 2)) + 11;
+ value = k_test_val;
+ prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 5);
+ EXPECT_EQ(k_test_val, value);
+ EXPECT_EQ(k_test_val, prev);
+
+ value = k_test_val;
+ prev = base::subtle::NoBarrier_CompareAndSwap(&value, k_test_val, 5);
+ EXPECT_EQ(5, value);
+ EXPECT_EQ(k_test_val, prev);
+}
+
+
+template <class AtomicType>
+static void TestAtomicExchange() {
+ AtomicType value = 0;
+ AtomicType new_value = base::subtle::NoBarrier_AtomicExchange(&value, 1);
+ EXPECT_EQ(1, value);
+ EXPECT_EQ(0, new_value);
+
+ // Use test value that has non-zero bits in both halves, more for testing
+ // 64-bit implementation on 32-bit platforms.
+ const AtomicType k_test_val = (GG_ULONGLONG(1) <<
+ (NUM_BITS(AtomicType) - 2)) + 11;
+ value = k_test_val;
+ new_value = base::subtle::NoBarrier_AtomicExchange(&value, k_test_val);
+ EXPECT_EQ(k_test_val, value);
+ EXPECT_EQ(k_test_val, new_value);
+
+ value = k_test_val;
+ new_value = base::subtle::NoBarrier_AtomicExchange(&value, 5);
+ EXPECT_EQ(5, value);
+ EXPECT_EQ(k_test_val, new_value);
+}
+
+
+template <class AtomicType>
+static void TestAtomicIncrementBounds() {
+ // Test at rollover boundary between int_max and int_min
+ AtomicType test_val = (GG_ULONGLONG(1) <<
+ (NUM_BITS(AtomicType) - 1));
+ AtomicType value = -1 ^ test_val;
+ AtomicType new_value = base::subtle::NoBarrier_AtomicIncrement(&value, 1);
+ EXPECT_EQ(test_val, value);
+ EXPECT_EQ(value, new_value);
+
+ base::subtle::NoBarrier_AtomicIncrement(&value, -1);
+ EXPECT_EQ(-1 ^ test_val, value);
+
+ // Test at 32-bit boundary for 64-bit atomic type.
+ test_val = GG_ULONGLONG(1) << (NUM_BITS(AtomicType) / 2);
+ value = test_val - 1;
+ new_value = base::subtle::NoBarrier_AtomicIncrement(&value, 1);
+ EXPECT_EQ(test_val, value);
+ EXPECT_EQ(value, new_value);
+
+ base::subtle::NoBarrier_AtomicIncrement(&value, -1);
+ EXPECT_EQ(test_val - 1, value);
+}
+
+// Return an AtomicType with the value 0xa5a5a5..
+template <class AtomicType>
+static AtomicType TestFillValue() {
+ AtomicType val = 0;
+ memset(&val, 0xa5, sizeof(AtomicType));
+ return val;
+}
+
+// This is a simple sanity check that values are correct. Not testing
+// atomicity
+template <class AtomicType>
+static void TestStore() {
+ const AtomicType kVal1 = TestFillValue<AtomicType>();
+ const AtomicType kVal2 = static_cast<AtomicType>(-1);
+
+ AtomicType value;
+
+ base::subtle::NoBarrier_Store(&value, kVal1);
+ EXPECT_EQ(kVal1, value);
+ base::subtle::NoBarrier_Store(&value, kVal2);
+ EXPECT_EQ(kVal2, value);
+
+ base::subtle::Acquire_Store(&value, kVal1);
+ EXPECT_EQ(kVal1, value);
+ base::subtle::Acquire_Store(&value, kVal2);
+ EXPECT_EQ(kVal2, value);
+
+ base::subtle::Release_Store(&value, kVal1);
+ EXPECT_EQ(kVal1, value);
+ base::subtle::Release_Store(&value, kVal2);
+ EXPECT_EQ(kVal2, value);
+}
+
+// This is a simple sanity check that values are correct. Not testing
+// atomicity
+template <class AtomicType>
+static void TestLoad() {
+ const AtomicType kVal1 = TestFillValue<AtomicType>();
+ const AtomicType kVal2 = static_cast<AtomicType>(-1);
+
+ AtomicType value;
+
+ value = kVal1;
+ EXPECT_EQ(kVal1, base::subtle::NoBarrier_Load(&value));
+ value = kVal2;
+ EXPECT_EQ(kVal2, base::subtle::NoBarrier_Load(&value));
+
+ value = kVal1;
+ EXPECT_EQ(kVal1, base::subtle::Acquire_Load(&value));
+ value = kVal2;
+ EXPECT_EQ(kVal2, base::subtle::Acquire_Load(&value));
+
+ value = kVal1;
+ EXPECT_EQ(kVal1, base::subtle::Release_Load(&value));
+ value = kVal2;
+ EXPECT_EQ(kVal2, base::subtle::Release_Load(&value));
+}
+
+TEST(AtomicOpsTest, Inc) {
+ TestAtomicIncrement<base::subtle::Atomic32>();
+ TestAtomicIncrement<base::subtle::AtomicWord>();
+}
+
+TEST(AtomicOpsTest, CompareAndSwap) {
+ TestCompareAndSwap<base::subtle::Atomic32>();
+ TestCompareAndSwap<base::subtle::AtomicWord>();
+}
+
+TEST(AtomicOpsTest, Exchange) {
+ TestAtomicExchange<base::subtle::Atomic32>();
+ TestAtomicExchange<base::subtle::AtomicWord>();
+}
+
+TEST(AtomicOpsTest, IncrementBounds) {
+ TestAtomicIncrementBounds<base::subtle::Atomic32>();
+ TestAtomicIncrementBounds<base::subtle::AtomicWord>();
+}
+
+TEST(AtomicOpsTest, Store) {
+ TestStore<base::subtle::Atomic32>();
+ TestStore<base::subtle::AtomicWord>();
+}
+
+TEST(AtomicOpsTest, Load) {
+ TestLoad<base::subtle::Atomic32>();
+ TestLoad<base::subtle::AtomicWord>();
+}
diff --git a/src/base/auto_reset.h b/src/base/auto_reset.h
new file mode 100644
index 0000000..32f138e
--- /dev/null
+++ b/src/base/auto_reset.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_AUTO_RESET_H_
+#define BASE_AUTO_RESET_H_
+
+#include "base/basictypes.h"
+
+// base::AutoReset<> is useful for setting a variable to a new value only within
+// a particular scope. An base::AutoReset<> object resets a variable to its
+// original value upon destruction, making it an alternative to writing
+// "var = false;" or "var = old_val;" at all of a block's exit points.
+//
+// This should be obvious, but note that an base::AutoReset<> instance should
+// have a shorter lifetime than its scoped_variable, to prevent invalid memory
+// writes when the base::AutoReset<> object is destroyed.
+
+namespace base {
+
+template<typename T>
+class AutoReset {
+ public:
+ AutoReset(T* scoped_variable, T new_value)
+ : scoped_variable_(scoped_variable),
+ original_value_(*scoped_variable) {
+ *scoped_variable_ = new_value;
+ }
+
+ ~AutoReset() { *scoped_variable_ = original_value_; }
+
+ private:
+ T* scoped_variable_;
+ T original_value_;
+
+ DISALLOW_COPY_AND_ASSIGN(AutoReset);
+};
+
+}
+
+#endif // BASE_AUTO_RESET_H_
diff --git a/src/base/base.gyp b/src/base/base.gyp
new file mode 100644
index 0000000..3838ff6
--- /dev/null
+++ b/src/base/base.gyp
@@ -0,0 +1,1322 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'includes': [
+ '../build/win_precompile.gypi',
+ 'base.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'base',
+ 'type': '<(component)',
+ 'toolsets': ['host', 'target'],
+ 'variables': {
+ 'base_target': 1,
+ 'enable_wexit_time_destructors': 1,
+ 'optimize': 'max',
+ },
+ 'dependencies': [
+ 'base_static',
+ 'allocator/allocator.gyp:allocator_extension_thunks',
+ '../testing/gtest.gyp:gtest_prod',
+ '../third_party/modp_b64/modp_b64.gyp:modp_b64',
+ 'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+ ],
+ # TODO(gregoryd): direct_dependent_settings should be shared with the
+ # 64-bit target, but it doesn't work due to a bug in gyp
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '..',
+ ],
+ },
+ 'conditions': [
+ ['use_glib==1', {
+ 'conditions': [
+ ['chromeos==1', {
+ 'sources/': [ ['include', '_chromeos\\.cc$'] ]
+ }],
+ ['linux_use_tcmalloc==0', {
+ 'defines': [
+ 'NO_TCMALLOC',
+ ],
+ 'direct_dependent_settings': {
+ 'defines': [
+ 'NO_TCMALLOC',
+ ],
+ },
+ }],
+ ['toolkit_uses_gtk==1', {
+ 'dependencies': [
+ '../build/linux/system.gyp:gtk',
+ ],
+ 'export_dependent_settings': [
+ '../build/linux/system.gyp:gtk',
+ ],
+ }],
+ ],
+ 'dependencies': [
+ 'symbolize',
+ '../build/linux/system.gyp:glib',
+ '../build/linux/system.gyp:x11',
+ 'xdg_mime',
+ ],
+ 'defines': [
+ 'USE_SYMBOLIZE',
+ ],
+ 'cflags': [
+ '-Wno-write-strings',
+ ],
+ 'export_dependent_settings': [
+ '../build/linux/system.gyp:glib',
+ '../build/linux/system.gyp:x11',
+ ],
+ }, { # use_glib!=1
+ 'sources/': [
+ ['exclude', '/xdg_user_dirs/'],
+ ['exclude', '_nss\\.cc$'],
+ ],
+ }],
+ ['OS == "android" and _toolset == "host"', {
+ # Base for host support is the minimum required to run the
+ # ssl false start blacklist tool. It requires further changes
+ # to generically support host builds (and tests).
+ # Note: when building for host, gyp has OS == "android",
+ # hence the *_android.cc files are included but the actual code
+ # doesn't have OS_ANDROID / ANDROID defined.
+ 'conditions': [
+ # Host build on linux depends on system.gyp::gtk as
+ # default linux build has TOOLKIT_GTK defined.
+ ['host_os == "linux"', {
+ 'sources/': [
+ ['include', '^atomicops_internals_x86_gcc\\.cc$'],
+ ],
+ 'dependencies': [
+ '../build/linux/system.gyp:gtk',
+ ],
+ 'export_dependent_settings': [
+ '../build/linux/system.gyp:gtk',
+ ],
+ }],
+ ['host_os == "mac"', {
+ 'sources/': [
+ ['exclude', '^native_library_linux\\.cc$'],
+ ['exclude', '^process_util_linux\\.cc$'],
+ ['exclude', '^sys_info_linux\\.cc$'],
+ ['exclude', '^sys_string_conversions_linux\\.cc$'],
+ ['exclude', '^worker_pool_linux\\.cc$'],
+ ],
+ }],
+ ],
+ }],
+ ['(OS == "android" or ((OS == "lb_shell" or OS == "starboard") and target_arch == "android")) and _toolset == "target"', {
+ 'dependencies': [
+ 'base_jni_headers',
+ 'symbolize',
+ '../third_party/ashmem/ashmem.gyp:ashmem',
+ '../third_party/icu/icu.gyp:icuuc',
+ ],
+ 'include_dirs': [
+ '<(SHARED_INTERMEDIATE_DIR)/base',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '-llog',
+ ],
+ },
+ 'defines': [
+ 'USE_SYMBOLIZE',
+ ],
+ 'sources!': [
+ 'debug/stack_trace_posix.cc',
+ ],
+ 'conditions' : [
+ ['target_arch == "ia32"', {
+ 'sources/': [
+ ['include', '^atomicops_internals_x86_gcc\\.cc$'],
+ ],
+ }],
+ ['target_arch != "android"', {
+ 'includes': [
+ '../build/android/cpufeatures.gypi',
+ ],
+ }],
+ ],
+ }],
+ ['(OS == "android" or ((OS == "lb_shell" or OS == "starboard") and target_arch == "android")) and _toolset == "target" and android_build_type == 0', {
+ 'dependencies': [
+ 'base_java',
+ ],
+ }],
+ ['((OS == "lb_shell" or OS == "starboard") and target_arch == "android")', {
+ 'link_settings': {
+ 'libraries': [
+ # for android_getCpuCount
+ '-lportable',
+ ],
+ },
+ }],
+ ['os_bsd==1', {
+ 'include_dirs': [
+ '/usr/local/include',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '-L/usr/local/lib -lexecinfo',
+ ],
+ },
+ }],
+ ['OS == "linux"', {
+ 'link_settings': {
+ 'libraries': [
+ # We need rt for clock_gettime().
+ '-lrt',
+ # For 'native_library_linux.cc'
+ '-ldl',
+ ],
+ },
+ }],
+ ['OS == "mac"', {
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/AppKit.framework',
+ '$(SDKROOT)/System/Library/Frameworks/ApplicationServices.framework',
+ '$(SDKROOT)/System/Library/Frameworks/Carbon.framework',
+ '$(SDKROOT)/System/Library/Frameworks/CoreFoundation.framework',
+ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+ '$(SDKROOT)/System/Library/Frameworks/IOKit.framework',
+ '$(SDKROOT)/System/Library/Frameworks/Security.framework',
+ ],
+ },
+ 'dependencies': [
+ '../third_party/mach_override/mach_override.gyp:mach_override',
+ ],
+ }],
+ ['OS == "ios"', {
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/CoreFoundation.framework',
+ '$(SDKROOT)/System/Library/Frameworks/CoreGraphics.framework',
+ '$(SDKROOT)/System/Library/Frameworks/CoreText.framework',
+ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+ '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+ ],
+ },
+ }],
+ ['OS != "win" and OS != "ios"', {
+ 'dependencies': ['../third_party/libevent/libevent.gyp:libevent'],
+ },],
+ ['component=="shared_library"', {
+ 'conditions': [
+ ['OS=="win"', {
+ 'sources!': [
+ 'debug/debug_on_start_win.cc',
+ ],
+ }],
+ ],
+ }],
+ ['OS == "lb_shell"', {
+ 'conditions': [
+ ['target_arch != "android"', {
+ 'dependencies!': [
+ '../third_party/libevent/libevent.gyp:libevent'
+ ],
+ }],
+ ['target_arch == "linux"', {
+ 'defines': [
+ 'USE_SYMBOLIZE',
+ ],
+ 'dependencies': [
+ 'symbolize',
+ ],
+ }],
+ ['target_arch == "ps3" and _toolset == "target"', {
+ # Script for resolving symbols, for use by stack_trace_ps3.cc
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)',
+ 'files': [
+ 'debug/addr2line_ps3.py',
+ ],
+ },
+ ],
+ 'dependencies': [
+ # On PS3, we use both posix emulation and starboard for
+ # threading. We depend on starboard for its TLS implementation.
+ # Eventually this will replace the posix_emulation below.
+ '<(DEPTH)/starboard/starboard.gyp:starboard',
+ ],
+ }],
+ # toolset can be host or target.
+ # (host in the case of e.g. protobuf compiler.)
+ # We only want posix_emulation for target builds.
+ ['_toolset == "target"', {
+ 'dependencies': [
+ '<(lbshell_root)/build/projects/posix_emulation.gyp:posix_emulation',
+ ],
+ }], # _toolset == "target"
+ ],
+ 'sources': [
+ 'debug/debugger_shell.cc',
+ 'debug/stack_trace_shell.cc',
+ 'guid_shell.cc',
+ 'safe_strerror_shell.cc',
+ 'sys_string_conversions_shell.cc',
+ 'test/test_file_util_shell.cc',
+ 'threading/thread_local_shell.cc',
+ 'threading/thread_local_storage_shell.cc',
+ 'threading/worker_pool_shell.cc',
+ ],
+ }], # OS=="lb_shell"
+ ['OS == "starboard"', {
+ 'conditions': [
+ ['_toolset == "target"', {
+ 'dependencies': [
+ '<(DEPTH)/starboard/starboard.gyp:starboard',
+ '<(DEPTH)/starboard/client_porting/eztime/eztime.gyp:eztime',
+ ],
+ }], # _toolset == "target"
+ ],
+ 'dependencies!': [
+ '../third_party/libevent/libevent.gyp:libevent'
+ ],
+ 'sources': [
+ 'base_paths_starboard.cc',
+ 'test/test_file_util_starboard.cc',
+ ],
+ }], # OS=="starboard"
+ ['OS == "lb_shell" or OS == "starboard"', {
+ 'sources!': [
+ 'file_descriptor_shuffle.cc',
+ ],
+ }], # OS == "lb_shell" or OS == "starboard"
+ ],
+ 'sources': [
+ 'third_party/nspr/prcpucfg.h',
+ 'third_party/nspr/prcpucfg_win.h',
+ 'third_party/nspr/prtypes.h',
+ 'third_party/xdg_user_dirs/xdg_user_dir_lookup.cc',
+ 'third_party/xdg_user_dirs/xdg_user_dir_lookup.h',
+ 'auto_reset.h',
+ 'event_recorder.h',
+ 'event_recorder_stubs.cc',
+ 'event_recorder_win.cc',
+ 'linux_util.cc',
+ 'linux_util.h',
+ 'md5.cc',
+ 'md5.h',
+ 'message_pump_android.cc',
+ 'message_pump_android.h',
+ 'message_pump_glib.cc',
+ 'message_pump_glib.h',
+ 'message_pump_gtk.cc',
+ 'message_pump_gtk.h',
+ 'message_pump_io_ios.cc',
+ 'message_pump_io_ios.h',
+ 'message_pump_observer.h',
+ 'message_pump_aurax11.cc',
+ 'message_pump_aurax11.h',
+ 'message_pump_libevent.cc',
+ 'message_pump_libevent.h',
+ 'message_pump_mac.h',
+ 'message_pump_mac.mm',
+ 'metrics/field_trial.cc',
+ 'metrics/field_trial.h',
+ 'posix/file_descriptor_shuffle.cc',
+ 'posix/file_descriptor_shuffle.h',
+ 'sync_socket.h',
+ 'sync_socket_win.cc',
+ 'sync_socket_posix.cc',
+ ],
+ },
+ {
+ 'target_name': 'base_i18n',
+ 'type': '<(component)',
+ 'variables': {
+ 'enable_wexit_time_destructors': 1,
+ 'optimize': 'max',
+ },
+ 'dependencies': [
+ 'base',
+ 'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+ '../third_party/icu/icu.gyp:icui18n',
+ '../third_party/icu/icu.gyp:icuuc',
+ ],
+ 'conditions': [
+ ['toolkit_uses_gtk==1', {
+ 'dependencies': [
+ # i18n/rtl.cc uses gtk
+ '../build/linux/system.gyp:gtk',
+ ],
+ }],
+ ['OS=="lb_shell"', {
+ 'dependencies': [
+ '<(lbshell_root)/build/projects/posix_emulation.gyp:posix_emulation',
+ ],
+ }],
+ ['OS=="starboard"', {
+ 'dependencies': [
+ '<(DEPTH)/starboard/starboard.gyp:starboard',
+ '<(DEPTH)/starboard/client_porting/icu_init/icu_init.gyp:icu_init',
+ ],
+ }],
+ ],
+ 'export_dependent_settings': [
+ 'base',
+ ],
+ 'defines': [
+ 'BASE_I18N_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'i18n/base_i18n_export.h',
+ 'i18n/bidi_line_iterator.cc',
+ 'i18n/bidi_line_iterator.h',
+ 'i18n/break_iterator.cc',
+ 'i18n/break_iterator.h',
+ 'i18n/char_iterator.cc',
+ 'i18n/char_iterator.h',
+ 'i18n/case_conversion.cc',
+ 'i18n/case_conversion.h',
+ 'i18n/file_util_icu.cc',
+ 'i18n/file_util_icu.h',
+ 'i18n/icu_encoding_detection.cc',
+ 'i18n/icu_encoding_detection.h',
+ 'i18n/icu_string_conversions.cc',
+ 'i18n/icu_string_conversions.h',
+ 'i18n/icu_util.cc',
+ 'i18n/icu_util.h',
+ 'i18n/number_formatting.cc',
+ 'i18n/number_formatting.h',
+ 'i18n/rtl.cc',
+ 'i18n/rtl.h',
+ 'i18n/string_search.cc',
+ 'i18n/string_search.h',
+ 'i18n/time_formatting.cc',
+ 'i18n/time_formatting.h',
+ ],
+ },
+ {
+ 'target_name': 'base_prefs',
+ 'type': '<(component)',
+ 'variables': {
+ 'enable_wexit_time_destructors': 1,
+ 'optimize': 'max',
+ },
+ 'dependencies': [
+ 'base',
+ ],
+ 'export_dependent_settings': [
+ 'base',
+ ],
+ 'defines': [
+ 'BASE_PREFS_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'prefs/default_pref_store.cc',
+ 'prefs/default_pref_store.h',
+ 'prefs/json_pref_store.cc',
+ 'prefs/json_pref_store.h',
+ 'prefs/overlay_user_pref_store.cc',
+ 'prefs/overlay_user_pref_store.h',
+ 'prefs/persistent_pref_store.h',
+ 'prefs/pref_observer.h',
+ 'prefs/pref_notifier.h',
+ 'prefs/pref_store.cc',
+ 'prefs/pref_store.h',
+ 'prefs/pref_value_map.cc',
+ 'prefs/pref_value_map.h',
+ 'prefs/public/pref_change_registrar.cc',
+ 'prefs/public/pref_change_registrar.h',
+ 'prefs/public/pref_member.cc',
+ 'prefs/public/pref_member.h',
+ 'prefs/public/pref_service_base.h',
+ 'prefs/value_map_pref_store.cc',
+ 'prefs/value_map_pref_store.h',
+ ],
+ 'conditions': [
+ ['OS == "starboard"', {
+ 'sources!': [
+ # Uses ImportantFileWriter, which is not supported by Starboard.
+ 'prefs/json_pref_store.cc',
+ 'prefs/json_pref_store.h',
+ ],
+ }], # OS=="starboard"
+ ],
+ },
+ {
+ # This is the subset of files from base that should not be used with a
+ # dynamic library. Note that this library cannot depend on base because
+ # base depends on base_static.
+ 'target_name': 'base_static',
+ 'type': 'static_library',
+ 'variables': {
+ 'enable_wexit_time_destructors': 1,
+ 'optimize': 'max',
+ },
+ 'toolsets': ['host', 'target'],
+ 'sources': [
+ 'base_switches.cc',
+ 'base_switches.h',
+ 'win/pe_image.cc',
+ 'win/pe_image.h',
+ ],
+ 'include_dirs': [
+ '..',
+ ],
+ 'conditions': [
+ ['OS == "lb_shell" or OS=="starboard"', {
+ 'sources/': [
+ ['exclude', '^win/'],
+ ],
+ }],
+ ],
+ },
+ {
+ # TODO(rvargas): Remove this when gyp finally supports a clean model.
+ # See bug 36232.
+ 'target_name': 'base_static_win64',
+ 'type': 'static_library',
+ 'sources': [
+ 'base_switches.cc',
+ 'base_switches.h',
+ 'win/pe_image.cc',
+ 'win/pe_image.h',
+ ],
+ 'sources!': [
+ # base64.cc depends on modp_b64.
+ 'base64.cc',
+ ],
+ 'include_dirs': [
+ '..',
+ ],
+ 'configurations': {
+ 'Common_Base': {
+ 'msvs_target_platform': 'x64',
+ },
+ },
+ 'defines': [
+ 'NACL_WIN64',
+ ],
+ # TODO(rvargas): Bug 78117. Remove this.
+ 'msvs_disabled_warnings': [
+ 4244,
+ ],
+ },
+ # Include this target for a main() function that simply instantiates
+ # and runs a base::TestSuite.
+ {
+ 'target_name': 'run_all_unittests',
+ 'type': 'static_library',
+ 'dependencies': [
+ 'test_support_base',
+ ],
+ 'sources': [
+ 'test/run_all_unittests.cc',
+ ],
+ },
+ {
+ 'target_name': 'base_unittests',
+ 'type': '<(gtest_target_type)',
+ 'sources': [
+ # Tests.
+ 'android/jni_android_unittest.cc',
+ 'android/jni_array_unittest.cc',
+ 'android/jni_string_unittest.cc',
+ 'android/path_utils_unittest.cc',
+ 'android/scoped_java_ref_unittest.cc',
+ 'at_exit_unittest.cc',
+ 'atomicops_unittest.cc',
+ 'base64_unittest.cc',
+ 'bind_helpers_unittest.cc',
+ 'bind_unittest.cc',
+ 'bind_unittest.nc',
+ 'bits_unittest.cc',
+ 'build_time_unittest.cc',
+ 'callback_unittest.cc',
+ 'callback_unittest.nc',
+ 'cancelable_callback_unittest.cc',
+ 'command_line_unittest.cc',
+ 'containers/linked_list_unittest.cc',
+ 'containers/mru_cache_unittest.cc',
+ 'containers/small_map_unittest.cc',
+ 'containers/stack_container_unittest.cc',
+ 'cpu_unittest.cc',
+ 'debug/leak_tracker_unittest.cc',
+ 'debug/stack_trace_unittest.cc',
+ 'debug/trace_event_unittest.cc',
+ 'debug/trace_event_unittest.h',
+ 'debug/trace_event_win_unittest.cc',
+ 'environment_unittest.cc',
+ 'file_path_unittest.cc',
+ 'file_util_proxy_unittest.cc',
+ 'file_util_unittest.cc',
+ 'file_version_info_unittest.cc',
+ 'files/dir_reader_posix_unittest.cc',
+ 'files/important_file_writer_unittest.cc',
+ 'files/scoped_temp_dir_unittest.cc',
+ 'gmock_unittest.cc',
+ 'guid_unittest.cc',
+ 'hi_res_timer_manager_unittest.cc',
+ 'id_map_unittest.cc',
+ 'i18n/break_iterator_unittest.cc',
+ 'i18n/char_iterator_unittest.cc',
+ 'i18n/case_conversion_unittest.cc',
+ 'i18n/file_util_icu_unittest.cc',
+ 'i18n/icu_string_conversions_unittest.cc',
+ 'i18n/number_formatting_unittest.cc',
+ 'i18n/rtl_unittest.cc',
+ 'i18n/string_search_unittest.cc',
+ 'i18n/time_formatting_unittest.cc',
+ 'ios/device_util_unittest.mm',
+ 'json/json_parser_unittest.cc',
+ 'json/json_reader_unittest.cc',
+ 'json/json_value_converter_unittest.cc',
+ 'json/json_value_serializer_unittest.cc',
+ 'json/json_writer_unittest.cc',
+ 'json/string_escape_unittest.cc',
+ 'lazy_instance_unittest.cc',
+ 'logging_unittest.cc',
+ 'mac/bind_objc_block_unittest.mm',
+ 'mac/foundation_util_unittest.mm',
+ 'mac/libdispatch_task_runner_unittest.cc',
+ 'mac/mac_util_unittest.mm',
+ 'mac/objc_property_releaser_unittest.mm',
+ 'mac/scoped_sending_event_unittest.mm',
+ 'md5_unittest.cc',
+ 'memory/aligned_memory_unittest.cc',
+ 'memory/linked_ptr_unittest.cc',
+ 'memory/ref_counted_memory_unittest.cc',
+ 'memory/ref_counted_unittest.cc',
+ 'memory/scoped_nsobject_unittest.mm',
+ 'memory/scoped_ptr_unittest.cc',
+ 'memory/scoped_ptr_unittest.nc',
+ 'memory/scoped_vector_unittest.cc',
+ 'memory/singleton_unittest.cc',
+ 'memory/weak_ptr_unittest.cc',
+ 'memory/weak_ptr_unittest.nc',
+ 'message_loop_proxy_impl_unittest.cc',
+ 'message_loop_proxy_unittest.cc',
+ 'message_loop_unittest.cc',
+ 'message_pump_glib_unittest.cc',
+ 'message_pump_io_ios_unittest.cc',
+ 'message_pump_libevent_unittest.cc',
+ 'metrics/sample_map_unittest.cc',
+ 'metrics/sample_vector_unittest.cc',
+ 'metrics/bucket_ranges_unittest.cc',
+ 'metrics/field_trial_unittest.cc',
+ 'metrics/histogram_unittest.cc',
+ 'metrics/sparse_histogram_unittest.cc',
+ 'metrics/stats_table_unittest.cc',
+ 'metrics/statistics_recorder_unittest.cc',
+ 'object_tracker.h',
+ 'observer_list_unittest.cc',
+ 'os_compat_android_unittest.cc',
+ 'path_service_unittest.cc',
+ 'pickle_unittest.cc',
+ 'platform_file_unittest.cc',
+ 'posix/file_descriptor_shuffle_unittest.cc',
+ 'pr_time_unittest.cc',
+ 'process_util_unittest.cc',
+ 'process_util_unittest_ios.cc',
+ 'process_util_unittest_mac.h',
+ 'process_util_unittest_mac.mm',
+ 'profiler/tracked_time_unittest.cc',
+ 'rand_util_unittest.cc',
+ 'scoped_native_library_unittest.cc',
+ 'scoped_observer.h',
+ 'sha1_unittest.cc',
+ 'shared_memory_unittest.cc',
+ 'stl_util_unittest.cc',
+ 'string16_unittest.cc',
+ 'string_number_conversions_unittest.cc',
+ 'string_piece_unittest.cc',
+ 'string_split_unittest.cc',
+ 'string_tokenizer_unittest.cc',
+ 'string_util_unittest.cc',
+ 'stringize_macros_unittest.cc',
+ 'stringprintf_unittest.cc',
+ 'synchronization/cancellation_flag_unittest.cc',
+ 'synchronization/condition_variable_unittest.cc',
+ 'synchronization/lock_unittest.cc',
+ 'synchronization/waitable_event_unittest.cc',
+ 'synchronization/waitable_event_watcher_unittest.cc',
+ 'sys_info_unittest.cc',
+ 'sys_string_conversions_mac_unittest.mm',
+ 'sys_string_conversions_unittest.cc',
+ 'system_monitor/system_monitor_unittest.cc',
+ 'task_runner_util_unittest.cc',
+ 'template_util_unittest.cc',
+ 'test/sequenced_worker_pool_owner.cc',
+ 'test/sequenced_worker_pool_owner.h',
+ 'test/trace_event_analyzer_unittest.cc',
+ 'test/time_helpers.cc',
+ 'test/time_helpers.h',
+ 'threading/non_thread_safe_unittest.cc',
+ 'threading/platform_thread_unittest.cc',
+ 'threading/sequenced_worker_pool_unittest.cc',
+ 'threading/simple_thread_unittest.cc',
+ 'threading/thread_checker_unittest.cc',
+ 'threading/thread_collision_warner_unittest.cc',
+ 'threading/thread_local_storage_unittest.cc',
+ 'threading/thread_local_unittest.cc',
+ 'threading/thread_unittest.cc',
+ 'threading/watchdog_unittest.cc',
+ 'threading/worker_pool_posix_unittest.cc',
+ 'threading/worker_pool_unittest.cc',
+ 'time_unittest.cc',
+ 'time_win_unittest.cc',
+ 'timer_unittest.cc',
+ 'tools_sanity_unittest.cc',
+ 'tracked_objects_unittest.cc',
+ 'tuple_unittest.cc',
+ 'utf_offset_string_conversions_unittest.cc',
+ 'utf_string_conversions_unittest.cc',
+ 'values_unittest.cc',
+ 'version_unittest.cc',
+ 'vlog_unittest.cc',
+ 'win/dllmain.cc',
+ 'win/enum_variant_unittest.cc',
+ 'win/event_trace_consumer_unittest.cc',
+ 'win/event_trace_controller_unittest.cc',
+ 'win/event_trace_provider_unittest.cc',
+ 'win/i18n_unittest.cc',
+ 'win/iunknown_impl_unittest.cc',
+ 'win/object_watcher_unittest.cc',
+ 'win/pe_image_unittest.cc',
+ 'win/registry_unittest.cc',
+ 'win/sampling_profiler_unittest.cc',
+ 'win/scoped_bstr_unittest.cc',
+ 'win/scoped_comptr_unittest.cc',
+ 'win/scoped_process_information_unittest.cc',
+ 'win/shortcut_unittest.cc',
+ 'win/startup_information_unittest.cc',
+ 'win/scoped_variant_unittest.cc',
+ 'win/win_util_unittest.cc',
+ 'win/wrapped_window_proc_unittest.cc',
+ ],
+ 'dependencies': [
+ 'base',
+ 'base_i18n',
+ 'base_static',
+ 'run_all_unittests',
+ 'test_support_base',
+ 'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+ '../testing/gmock.gyp:gmock',
+ '../testing/gtest.gyp:gtest',
+ '../third_party/icu/icu.gyp:icui18n',
+ '../third_party/icu/icu.gyp:icuuc',
+ ],
+ 'includes': ['../build/nocompile.gypi'],
+ 'variables': {
+ # TODO(ajwong): Is there a way to autodetect this?
+ 'module_dir': 'base'
+ },
+ 'conditions': [
+ ['OS == "android"', {
+ 'dependencies': [
+ 'android/jni_generator/jni_generator.gyp:jni_generator_tests',
+ ],
+ 'conditions': [
+ ['gtest_target_type == "shared_library"', {
+ 'dependencies': [
+ '../testing/android/native_test.gyp:native_test_native_code',
+ ],
+ }],
+ ],
+ 'sources!': [
+ # Broken on Android, and already disabled there.
+ 'debug/stack_trace_unittest.cc',
+ ],
+ }],
+ ['OS == "ios"', {
+ 'sources/': [
+ # Only test the iOS-meaningful portion of process_utils.
+ ['exclude', '^process_util_unittest'],
+ ['include', '^process_util_unittest_ios\\.cc$'],
+ # Requires spawning processes.
+ ['exclude', '^metrics/stats_table_unittest\\.cc$'],
+ # iOS does not use message_pump_libevent.
+ ['exclude', '^message_pump_libevent_unittest\\.cc$'],
+ ],
+ 'conditions': [
+ ['coverage != 0', {
+ 'sources!': [
+ # These sources can't be built with coverage due to a toolchain
+ # bug: http://openradar.appspot.com/radar?id=1499403
+ 'json/json_reader_unittest.cc',
+ 'string_piece_unittest.cc',
+
+ # These tests crash when run with coverage turned on due to an
+ # issue with llvm_gcda_increment_indirect_counter:
+ # http://crbug.com/156058
+ 'debug/trace_event_unittest.cc',
+ 'debug/trace_event_unittest.h',
+ 'logging_unittest.cc',
+ 'string_util_unittest.cc',
+ 'test/trace_event_analyzer_unittest.cc',
+ 'utf_offset_string_conversions_unittest.cc',
+ ],
+ }],
+ ],
+ 'actions': [
+ {
+ 'action_name': 'copy_test_data',
+ 'variables': {
+ 'test_data_files': [
+ 'data/json/bom_feff.json',
+ 'data/file_util_unittest',
+ ],
+ 'test_data_prefix': 'base',
+ },
+ 'includes': [ '../build/copy_test_data_ios.gypi' ],
+ },
+ ],
+ }],
+ ['cobalt==1', {
+ 'actions': [
+ {
+ 'action_name': 'copy_test_data',
+ 'variables': {
+ 'input_files': [
+ 'data/json',
+ 'data/file_util_unittest',
+ ],
+ 'output_dir': 'base/data',
+ },
+ 'includes': [ '../cobalt/build/copy_test_data.gypi' ],
+ },
+ ],
+ }],
+ ['use_glib==1', {
+ 'sources!': [
+ 'file_version_info_unittest.cc',
+ ],
+ 'conditions': [
+ [ 'linux_use_tcmalloc==1', {
+ 'dependencies': [
+ 'allocator/allocator.gyp:allocator',
+ ],
+ },
+ ],
+ [ 'toolkit_uses_gtk==1', {
+ 'sources': [
+ 'nix/xdg_util_unittest.cc',
+ ],
+ 'dependencies': [
+ '../build/linux/system.gyp:gtk',
+ ]
+ }],
+ ],
+ 'dependencies': [
+ '../build/linux/system.gyp:glib',
+ '../build/linux/system.gyp:ssl',
+ '../tools/xdisplaycheck/xdisplaycheck.gyp:xdisplaycheck',
+ ],
+ }, { # use_glib!=1
+ 'sources!': [
+ 'message_pump_glib_unittest.cc',
+ ]
+ }],
+ # This is needed to trigger the dll copy step on windows.
+ # TODO(mark): This should not be necessary.
+ ['OS == "win"', {
+ 'dependencies': [
+ '../third_party/icu/icu.gyp:icudata',
+ ],
+ 'sources!': [
+ 'file_descriptor_shuffle_unittest.cc',
+ 'files/dir_reader_posix_unittest.cc',
+ 'threading/worker_pool_posix_unittest.cc',
+ 'message_pump_libevent_unittest.cc',
+ ],
+ }, { # OS != "win"
+ 'dependencies': [
+ '../third_party/libevent/libevent.gyp:libevent'
+ ],
+ 'sources/': [
+ ['exclude', '^win/'],
+ ],
+ 'sources!': [
+ 'debug/trace_event_win_unittest.cc',
+ 'time_win_unittest.cc',
+ 'win/win_util_unittest.cc',
+ ],
+ }],
+ ['OS == "lb_shell" or OS == "starboard"', {
+ 'sources!': [
+ 'environment_unittest.cc',
+ 'files/important_file_writer_unittest.cc',
+ # We don't use field trials (an experiments framework) in Cobalt,
+ # and these tests depend on the current date being set correctly,
+ # so do not run them.
+ 'metrics/field_trial_unittest.cc',
+ 'metrics/stats_table_unittest.cc',
+ 'process_util_unittest.cc',
+ 'scoped_native_library_unittest.cc',
+ 'shared_memory_unittest.cc',
+ 'synchronization/waitable_event_watcher_unittest.cc',
+ ],
+ 'sources': [
+ 'circular_buffer_shell_unittest.cc',
+ 'optional_unittest.cc',
+ 'state_machine_shell_unittest.cc',
+ ],
+ 'conditions': [
+ ['target_arch != "android" or OS == "starboard"', {
+ 'dependencies!': [
+ '../third_party/libevent/libevent.gyp:libevent'
+ ],
+ 'sources!': [
+ 'message_pump_libevent_unittest.cc',
+ ],
+ }],
+ ],
+ }],
+ ], # conditions
+ 'target_conditions': [
+ ['OS == "ios"', {
+ 'sources/': [
+ # Pull in specific Mac files for iOS (which have been filtered out
+ # by file name rules).
+ ['include', '^mac/objc_property_releaser_unittest\\.mm$'],
+ ['include', '^mac/bind_objc_block_unittest\\.mm$'],
+ ['include', '^sys_string_conversions_mac_unittest\\.mm$'],
+ ],
+ }],
+ ], # target_conditions
+ 'msvs_disabled_warnings': [
+ 4800, # forcing value to bool 'true' or 'false' (performance warning)
+ ],
+ },
+ {
+ 'target_name': 'test_support_base',
+ 'type': 'static_library',
+ 'dependencies': [
+ 'base',
+ 'base_static',
+ 'base_i18n',
+ '../testing/gmock.gyp:gmock',
+ '../testing/gtest.gyp:gtest',
+ ],
+ 'export_dependent_settings': [
+ 'base',
+ ],
+ 'conditions': [
+ ['cobalt==1', {
+ 'dependencies': [
+ # Platform delegate is used to perform system specific
+ # initialization logic. This is a temporary solution and the code
+ # should eventually move into the chromium/base code.
+ '<(DEPTH)/cobalt/deprecated/deprecated.gyp:platform_delegate',
+ ],
+ }],
+ ['toolkit_uses_gtk==1', {
+ 'dependencies': [
+ # test_suite initializes GTK.
+ '../build/linux/system.gyp:gtk',
+ ],
+ }],
+ ['os_posix==0', {
+ 'sources!': [
+ 'test/scoped_locale.cc',
+ 'test/scoped_locale.h',
+ ],
+ }],
+ ['os_bsd==1', {
+ 'sources!': [
+ 'test/test_file_util_linux.cc',
+ ],
+ }],
+ ['OS=="win"', {
+ 'direct_dependent_settings': {
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'DelayLoadDLLs': [
+ 'propsys.dll',
+ ],
+ },
+ },
+ },
+ }],
+ ],
+ 'sources': [
+ 'perftimer.cc',
+ 'test/main_hook.cc',
+ 'test/main_hook.h',
+ 'test/main_hook_ios.mm',
+ 'test/mock_chrome_application_mac.h',
+ 'test/mock_chrome_application_mac.mm',
+ 'test/mock_devices_changed_observer.cc',
+ 'test/mock_devices_changed_observer.h',
+ 'test/mock_time_provider.cc',
+ 'test/mock_time_provider.h',
+ 'test/multiprocess_test.cc',
+ 'test/multiprocess_test.h',
+ 'test/multiprocess_test_android.cc',
+ 'test/perf_test_suite.cc',
+ 'test/perf_test_suite.h',
+ 'test/scoped_locale.cc',
+ 'test/scoped_locale.h',
+ 'test/scoped_path_override.cc',
+ 'test/scoped_path_override.h',
+ 'test/sequenced_task_runner_test_template.cc',
+ 'test/sequenced_task_runner_test_template.h',
+ 'test/task_runner_test_template.cc',
+ 'test/task_runner_test_template.h',
+ 'test/test_file_util.h',
+ 'test/test_file_util_linux.cc',
+ 'test/test_file_util_mac.cc',
+ 'test/test_file_util_posix.cc',
+ 'test/test_file_util_win.cc',
+ 'test/test_listener_ios.h',
+ 'test/test_listener_ios.mm',
+ 'test/test_reg_util_win.cc',
+ 'test/test_reg_util_win.h',
+ 'test/test_shortcut_win.cc',
+ 'test/test_shortcut_win.h',
+ 'test/test_suite.cc',
+ 'test/test_suite.h',
+ 'test/test_support_android.cc',
+ 'test/test_support_android.h',
+ 'test/test_support_ios.h',
+ 'test/test_support_ios.mm',
+ 'test/test_switches.cc',
+ 'test/test_switches.h',
+ 'test/test_timeouts.cc',
+ 'test/test_timeouts.h',
+ 'test/thread_test_helper.cc',
+ 'test/thread_test_helper.h',
+ 'test/trace_event_analyzer.cc',
+ 'test/trace_event_analyzer.h',
+ 'test/values_test_util.cc',
+ 'test/values_test_util.h',
+ ],
+ 'target_conditions': [
+ ['OS == "ios"', {
+ 'sources/': [
+ # Pull in specific Mac files for iOS (which have been filtered out
+ # by file name rules).
+ ['include', '^test/test_file_util_mac\\.cc$'],
+ ],
+ }],
+ ['OS == "lb_shell" or OS=="starboard"', {
+ 'sources/': [
+ ['exclude', 'test/multiprocess_test'],
+ ],
+ 'sources!': [
+ 'perftimer.cc',
+ ],
+ 'sources': [
+ 'perftimer_starboard.cc',
+ ],
+ }],
+ ], # target_conditions
+ },
+ {
+ 'target_name': 'test_support_perf',
+ 'type': 'static_library',
+ 'dependencies': [
+ 'base',
+ '../testing/gtest.gyp:gtest',
+ ],
+ 'sources': [
+ 'perftimer.cc',
+ 'test/run_all_perftests.cc',
+ ],
+ 'direct_dependent_settings': {
+ 'defines': [
+ 'PERF_TEST',
+ ],
+ },
+ 'conditions': [
+ ['toolkit_uses_gtk==1', {
+ 'dependencies': [
+ # Needed to handle the #include chain:
+ # base/test/perf_test_suite.h
+ # base/test/test_suite.h
+ # gtk/gtk.h
+ '../build/linux/system.gyp:gtk',
+ ],
+ }],
+ ['OS=="starboard"', {
+ 'sources!': [
+ 'perftimer.cc',
+ ],
+ 'sources': [
+ 'perftimer_starboard.cc',
+ ],
+ }],
+ ],
+ },
+ ],
+ 'conditions': [
+ ['OS!="ios"', {
+ 'targets': [
+ {
+ 'target_name': 'check_example',
+ 'type': 'executable',
+ 'sources': [
+ 'check_example.cc',
+ ],
+ 'dependencies': [
+ 'base',
+ ],
+ },
+ ],
+ }],
+ ['OS == "win"', {
+ 'targets': [
+ {
+ 'target_name': 'base_nacl_win64',
+ 'type': '<(component)',
+ 'variables': {
+ 'base_target': 1,
+ },
+ 'dependencies': [
+ 'base_static_win64',
+ 'allocator/allocator.gyp:allocator_extension_thunks_win64',
+ 'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations_win64',
+ ],
+ # TODO(gregoryd): direct_dependent_settings should be shared with the
+ # 32-bit target, but it doesn't work due to a bug in gyp
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '..',
+ ],
+ },
+ 'defines': [
+ '<@(nacl_win64_defines)',
+ ],
+ 'sources!': [
+ # base64.cc depends on modp_b64.
+ 'base64.cc',
+ ],
+ 'configurations': {
+ 'Common_Base': {
+ 'msvs_target_platform': 'x64',
+ },
+ },
+ 'conditions': [
+ ['component == "shared_library"', {
+ 'sources!': [
+ 'debug/debug_on_start_win.cc',
+ ],
+ }],
+ ],
+ },
+ {
+ 'target_name': 'base_i18n_nacl_win64',
+ 'type': '<(component)',
+ # TODO(gregoryd): direct_dependent_settings should be shared with the
+ # 32-bit target, but it doesn't work due to a bug in gyp
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '..',
+ ],
+ },
+ 'defines': [
+ '<@(nacl_win64_defines)',
+ 'BASE_I18N_IMPLEMENTATION',
+ ],
+ 'include_dirs': [
+ '..',
+ ],
+ 'sources': [
+ 'i18n/icu_util_nacl_win64.cc',
+ ],
+ 'configurations': {
+ 'Common_Base': {
+ 'msvs_target_platform': 'x64',
+ },
+ },
+ },
+ ],
+ }],
+ ['os_posix==1 and OS!="mac" and OS!="ios" and (OS!="lb_shell" or target_arch in ("android", "linux"))', {
+ 'targets': [
+ {
+ 'target_name': 'symbolize',
+ 'type': 'static_library',
+ 'toolsets': ['host', 'target'],
+ 'variables': {
+ 'chromium_code': 0,
+ },
+ 'conditions': [
+ ['OS == "solaris"', {
+ 'include_dirs': [
+ '/usr/gnu/include',
+ '/usr/gnu/include/libelf',
+ ],
+ },],
+ ],
+ 'cflags': [
+ '-Wno-sign-compare',
+ ],
+ 'cflags!': [
+ '-Wextra',
+ ],
+ 'sources': [
+ 'third_party/symbolize/config.h',
+ 'third_party/symbolize/demangle.cc',
+ 'third_party/symbolize/demangle.h',
+ 'third_party/symbolize/glog/logging.h',
+ 'third_party/symbolize/glog/raw_logging.h',
+ 'third_party/symbolize/symbolize.cc',
+ 'third_party/symbolize/symbolize.h',
+ 'third_party/symbolize/utilities.h',
+ ],
+ 'include_dirs': [
+ '..',
+ ],
+ },
+ {
+ 'target_name': 'xdg_mime',
+ 'type': 'static_library',
+ 'toolsets': ['host', 'target'],
+ 'variables': {
+ 'chromium_code': 0,
+ },
+ 'cflags!': [
+ '-Wextra',
+ ],
+ 'sources': [
+ 'third_party/xdg_mime/xdgmime.c',
+ 'third_party/xdg_mime/xdgmime.h',
+ 'third_party/xdg_mime/xdgmimealias.c',
+ 'third_party/xdg_mime/xdgmimealias.h',
+ 'third_party/xdg_mime/xdgmimecache.c',
+ 'third_party/xdg_mime/xdgmimecache.h',
+ 'third_party/xdg_mime/xdgmimeglob.c',
+ 'third_party/xdg_mime/xdgmimeglob.h',
+ 'third_party/xdg_mime/xdgmimeicon.c',
+ 'third_party/xdg_mime/xdgmimeicon.h',
+ 'third_party/xdg_mime/xdgmimeint.c',
+ 'third_party/xdg_mime/xdgmimeint.h',
+ 'third_party/xdg_mime/xdgmimemagic.c',
+ 'third_party/xdg_mime/xdgmimemagic.h',
+ 'third_party/xdg_mime/xdgmimeparent.c',
+ 'third_party/xdg_mime/xdgmimeparent.h',
+ ],
+ },
+ ],
+ }],
+ ['OS == "android" or ((OS == "lb_shell" or OS == "starboard") and target_arch == "android")', {
+ 'targets': [
+ {
+ 'target_name': 'base_jni_headers',
+ 'type': 'none',
+ 'sources': [
+ 'android/java/src/org/chromium/base/BuildInfo.java',
+ 'android/java/src/org/chromium/base/CpuFeatures.java',
+ 'android/java/src/org/chromium/base/LocaleUtils.java',
+ 'android/java/src/org/chromium/base/PathService.java',
+ 'android/java/src/org/chromium/base/PathUtils.java',
+ 'android/java/src/org/chromium/base/SystemMessageHandler.java',
+ 'android/java/src/org/chromium/base/SystemMonitor.java',
+ ],
+ 'variables': {
+ 'jni_gen_dir': 'base',
+ },
+ 'includes': [ '../build/jni_generator.gypi' ],
+ },
+ {
+ 'target_name': 'base_java',
+ 'type': 'none',
+ 'variables': {
+ 'package_name': 'base',
+ 'java_in_dir': '../base/android/java',
+ },
+ 'includes': [ '../build/java.gypi' ],
+ },
+ {
+ 'target_name': 'base_java_test_support',
+ 'type': 'none',
+ 'dependencies': [
+ 'base_java',
+ ],
+ 'variables': {
+ 'package_name': 'base_javatests',
+ 'java_in_dir': '../base/test/android/javatests',
+ },
+ 'includes': [ '../build/java.gypi' ],
+ },
+ ],
+ }],
+ ['OS == "win"', {
+ 'targets': [
+ {
+ 'target_name': 'debug_message',
+ 'type': 'executable',
+ 'sources': [
+ 'debug_message.cc',
+ ],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'SubSystem': '2', # Set /SUBSYSTEM:WINDOWS
+ },
+ },
+ },
+ ],
+ }],
+ ['cobalt==1', {
+ 'targets': [
+ {
+ 'target_name': 'base_unittests_deploy',
+ 'type': 'none',
+ 'dependencies': [
+ 'base_unittests',
+ ],
+ 'variables': {
+ 'executable_name': 'base_unittests',
+ },
+ 'includes': [ '../cobalt/build/deploy.gypi' ],
+ },
+ ],
+ }],
+ # Special target to wrap a gtest_target_type == shared_library
+ # base_unittests into an android apk for execution.
+ # TODO(jrg): lib.target comes from _InstallableTargetInstallPath()
+ # in the gyp make generator. What is the correct way to extract
+ # this path from gyp and into 'raw' for input to antfiles?
+ # Hard-coding in the gypfile seems a poor choice.
+ ['(OS == "android" and gtest_target_type == "shared_library") or ((OS == "lb_shell" or OS == "starboard") and target_arch == "android")', {
+ 'targets': [
+ {
+ 'target_name': 'base_unittests_apk',
+ 'type': 'none',
+ 'dependencies': [
+ 'base_java',
+ 'base_unittests',
+ ],
+ 'variables': {
+ 'test_suite_name': 'base_unittests',
+ 'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)base_unittests<(SHARED_LIB_SUFFIX)',
+ },
+ 'includes': [ '../build/apk_test.gypi' ],
+ },
+ ],
+ }],
+ ['test_isolation_mode != "noop"', {
+ 'targets': [
+ {
+ 'target_name': 'base_unittests_run',
+ 'type': 'none',
+ 'dependencies': [
+ 'base_unittests',
+ ],
+ 'includes': [
+ '../build/isolate.gypi',
+ 'base_unittests.isolate',
+ ],
+ 'sources': [
+ 'base_unittests.isolate',
+ ],
+ },
+ ],
+ }],
+ ],
+}
diff --git a/src/base/base.gypi b/src/base/base.gypi
new file mode 100644
index 0000000..fde1a96
--- /dev/null
+++ b/src/base/base.gypi
@@ -0,0 +1,858 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'target_defaults': {
+ 'variables': {
+ 'base_target': 0,
+ },
+ 'target_conditions': [
+ # This part is shared between the targets defined below.
+ ['base_target==1', {
+ 'sources': [
+ '../build/build_config.h',
+ 'third_party/dmg_fp/dmg_fp.h',
+ 'third_party/dmg_fp/g_fmt.cc',
+ 'third_party/dmg_fp/dtoa_wrapper.cc',
+ 'third_party/icu/icu_utf.cc',
+ 'third_party/icu/icu_utf.h',
+ 'third_party/nspr/prtime.cc',
+ 'third_party/nspr/prtime.h',
+ 'third_party/nspr/prcpucfg_linux.h',
+ 'third_party/xdg_mime/xdgmime.h',
+ 'allocator/allocator_extension.cc',
+ 'allocator/allocator_extension.h',
+ 'allocator/type_profiler_control.cc',
+ 'allocator/type_profiler_control.h',
+ 'android/base_jni_registrar.cc',
+ 'android/base_jni_registrar.h',
+ 'android/build_info.cc',
+ 'android/build_info.h',
+ 'android/cpu_features.cc',
+ 'android/scoped_java_ref.cc',
+ 'android/scoped_java_ref.h',
+ 'android/jni_android.cc',
+ 'android/jni_android.h',
+ 'android/jni_array.cc',
+ 'android/jni_array.h',
+ 'android/jni_helper.cc',
+ 'android/jni_helper.h',
+ 'android/jni_registrar.cc',
+ 'android/jni_registrar.h',
+ 'android/jni_string.cc',
+ 'android/jni_string.h',
+ 'android/locale_utils.cc',
+ 'android/locale_utils.h',
+ 'android/path_service_android.cc',
+ 'android/path_service_android.h',
+ 'android/path_utils.cc',
+ 'android/path_utils.h',
+ 'at_exit.cc',
+ 'at_exit.h',
+ 'atomic_ref_count.h',
+ 'atomic_sequence_num.h',
+ 'atomicops.h',
+ 'atomicops_internals_gcc.h',
+ 'atomicops_internals_mac.h',
+ 'atomicops_internals_tsan.h',
+ 'atomicops_internals_x86_gcc.cc',
+ 'atomicops_internals_x86_gcc.h',
+ 'atomicops_internals_x86_msvc.h',
+ 'base_export.h',
+ 'base_paths.cc',
+ 'base_paths.h',
+ 'base_paths_android.cc',
+ 'base_paths_android.h',
+ 'base_paths_mac.h',
+ 'base_paths_mac.mm',
+ 'base_paths_posix.cc',
+ 'base_paths_posix.h',
+ 'base_paths_win.cc',
+ 'base_paths_win.h',
+ 'base_switches.h',
+ 'base64.cc',
+ 'base64.h',
+ 'basictypes.h',
+ 'bind.h',
+ 'bind_helpers.cc',
+ 'bind_helpers.h',
+ 'bind_internal.h',
+ 'bind_internal_functor.h',
+ 'bind_internal_win.h',
+ 'bits.h',
+ 'build_time.cc',
+ 'build_time.h',
+ 'callback.h',
+ 'callback_helpers.h',
+ 'callback_internal.cc',
+ 'callback_internal.h',
+ 'cancelable_callback.h',
+ 'chromeos/chromeos_version.cc',
+ 'chromeos/chromeos_version.h',
+ 'command_line.cc',
+ 'command_line.h',
+ 'compiler_specific.h',
+ 'containers/linked_hash_map.h',
+ 'containers/linked_list.h',
+ 'containers/mru_cache.h',
+ 'containers/small_map.h',
+ 'containers/stack_container.h',
+ 'cpu.cc',
+ 'cpu.h',
+ 'critical_closure.h',
+ 'critical_closure_ios.mm',
+ 'debug/alias.cc',
+ 'debug/alias.h',
+ 'debug/debug_on_start_win.cc',
+ 'debug/debug_on_start_win.h',
+ 'debug/debugger.cc',
+ 'debug/debugger.h',
+ 'debug/debugger_posix.cc',
+ 'debug/debugger_win.cc',
+ # This file depends on files from the 'allocator' target,
+ # but this target does not depend on 'allocator' (see
+ # allocator.gyp for details).
+ 'debug/leak_annotations.h',
+ 'debug/leak_tracker.h',
+ 'debug/profiler.cc',
+ 'debug/profiler.h',
+ 'debug/stack_trace.cc',
+ 'debug/stack_trace.h',
+ 'debug/stack_trace_android.cc',
+ 'debug/stack_trace_ios.mm',
+ 'debug/stack_trace_posix.cc',
+ 'debug/stack_trace_win.cc',
+ 'debug/trace_event.cc',
+ 'debug/trace_event.h',
+ 'debug/trace_event_android.cc',
+ 'debug/trace_event_impl.cc',
+ 'debug/trace_event_impl.h',
+ 'debug/trace_event_win.cc',
+ 'environment.cc',
+ 'environment.h',
+ 'file_descriptor_posix.h',
+ 'file_path.cc',
+ 'file_path.h',
+ 'file_util.cc',
+ 'file_util.h',
+ 'file_util_android.cc',
+ 'file_util_linux.cc',
+ 'file_util_mac.mm',
+ 'file_util_posix.cc',
+ 'file_util_win.cc',
+ 'file_util_proxy.cc',
+ 'file_util_proxy.h',
+ 'file_version_info.h',
+ 'file_version_info_mac.h',
+ 'file_version_info_mac.mm',
+ 'file_version_info_win.cc',
+ 'file_version_info_win.h',
+ 'files/dir_reader_fallback.h',
+ 'files/dir_reader_dirent.h',
+ 'files/dir_reader_linux.h',
+ 'files/dir_reader_posix.h',
+ 'files/file_path_watcher.cc',
+ 'files/file_path_watcher.h',
+ 'files/file_path_watcher_kqueue.cc',
+ 'files/file_path_watcher_linux.cc',
+ 'files/file_path_watcher_stub.cc',
+ 'files/file_path_watcher_win.cc',
+ 'files/important_file_writer.h',
+ 'files/important_file_writer.cc',
+ 'files/scoped_temp_dir.cc',
+ 'files/scoped_temp_dir.h',
+ 'float_util.h',
+ 'format_macros.h',
+ 'gtest_prod_util.h',
+ 'guid.cc',
+ 'guid.h',
+ 'guid_posix.cc',
+ 'guid_win.cc',
+ 'hash.cc',
+ 'hash.h',
+ 'hash_tables.h',
+ 'hi_res_timer_manager_posix.cc',
+ 'hi_res_timer_manager_win.cc',
+ 'hi_res_timer_manager.h',
+ 'id_map.h',
+ 'ios/device_util.h',
+ 'ios/device_util.mm',
+ 'ios/ios_util.h',
+ 'ios/ios_util.mm',
+ 'ios/scoped_critical_action.h',
+ 'ios/scoped_critical_action.mm',
+ 'json/json_file_value_serializer.cc',
+ 'json/json_file_value_serializer.h',
+ 'json/json_parser.cc',
+ 'json/json_parser.h',
+ 'json/json_reader.cc',
+ 'json/json_reader.h',
+ 'json/json_string_value_serializer.cc',
+ 'json/json_string_value_serializer.h',
+ 'json/json_value_converter.h',
+ 'json/json_writer.cc',
+ 'json/json_writer.h',
+ 'json/string_escape.cc',
+ 'json/string_escape.h',
+ 'lazy_instance.cc',
+ 'lazy_instance.h',
+ 'location.cc',
+ 'location.h',
+ 'logging.cc',
+ 'logging.h',
+ 'logging_win.cc',
+ 'logging_win.h',
+ 'mac/authorization_util.h',
+ 'mac/authorization_util.mm',
+ 'mac/bind_objc_block.h',
+ 'mac/bind_objc_block.mm',
+ 'mac/bundle_locations.h',
+ 'mac/bundle_locations.mm',
+ 'mac/cocoa_protocols.h',
+ 'mac/crash_logging.h',
+ 'mac/crash_logging.mm',
+ 'mac/foundation_util.h',
+ 'mac/foundation_util.mm',
+ 'mac/launchd.cc',
+ 'mac/launchd.h',
+ 'mac/libdispatch_task_runner.cc',
+ 'mac/libdispatch_task_runner.h',
+ 'mac/mac_logging.h',
+ 'mac/mac_logging.cc',
+ 'mac/mac_util.h',
+ 'mac/mac_util.mm',
+ 'mac/objc_property_releaser.h',
+ 'mac/objc_property_releaser.mm',
+ 'mac/os_crash_dumps.cc',
+ 'mac/os_crash_dumps.h',
+ 'mac/scoped_aedesc.h',
+ 'mac/scoped_authorizationref.h',
+ 'mac/scoped_cftyperef.h',
+ 'mac/scoped_ioobject.h',
+ 'mac/scoped_launch_data.h',
+ 'mac/scoped_mach_port.cc',
+ 'mac/scoped_mach_port.h',
+ 'mac/scoped_nsautorelease_pool.h',
+ 'mac/scoped_nsautorelease_pool.mm',
+ 'mac/scoped_nsexception_enabler.h',
+ 'mac/scoped_nsexception_enabler.mm',
+ 'mac/scoped_sending_event.h',
+ 'mac/scoped_sending_event.mm',
+ 'mach_ipc_mac.h',
+ 'mach_ipc_mac.mm',
+ 'memory/aligned_memory.cc',
+ 'memory/aligned_memory.h',
+ 'memory/linked_ptr.h',
+ 'memory/manual_constructor.h',
+ 'memory/raw_scoped_refptr_mismatch_checker.h',
+ 'memory/ref_counted.cc',
+ 'memory/ref_counted.h',
+ 'memory/ref_counted_memory.cc',
+ 'memory/ref_counted_memory.h',
+ 'memory/scoped_handle.h',
+ 'memory/scoped_nsobject.h',
+ 'memory/scoped_open_process.h',
+ 'memory/scoped_policy.h',
+ 'memory/scoped_ptr.h',
+ 'memory/scoped_vector.h',
+ 'memory/singleton.cc',
+ 'memory/singleton.h',
+ 'memory/weak_ptr.cc',
+ 'memory/weak_ptr.h',
+ 'message_loop.cc',
+ 'message_loop.h',
+ 'message_loop_proxy.cc',
+ 'message_loop_proxy.h',
+ 'message_loop_proxy_impl.cc',
+ 'message_loop_proxy_impl.h',
+ 'message_pump.cc',
+ 'message_pump.h',
+ 'message_pump_android.cc',
+ 'message_pump_android.h',
+ 'message_pump_default.cc',
+ 'message_pump_default.h',
+ 'message_pump_win.cc',
+ 'message_pump_win.h',
+ 'metrics/sample_map.cc',
+ 'metrics/sample_map.h',
+ 'metrics/sample_vector.cc',
+ 'metrics/sample_vector.h',
+ 'metrics/bucket_ranges.cc',
+ 'metrics/bucket_ranges.h',
+ 'metrics/histogram.cc',
+ 'metrics/histogram.h',
+ 'metrics/histogram_base.cc',
+ 'metrics/histogram_base.h',
+ 'metrics/histogram_flattener.h',
+ 'metrics/histogram_samples.cc',
+ 'metrics/histogram_samples.h',
+ 'metrics/histogram_snapshot_manager.cc',
+ 'metrics/histogram_snapshot_manager.h',
+ 'metrics/sparse_histogram.cc',
+ 'metrics/sparse_histogram.h',
+ 'metrics/statistics_recorder.cc',
+ 'metrics/statistics_recorder.h',
+ 'metrics/stats_counters.cc',
+ 'metrics/stats_counters.h',
+ 'metrics/stats_table.cc',
+ 'metrics/stats_table.h',
+ 'move.h',
+ 'native_library.h',
+ 'native_library_mac.mm',
+ 'native_library_posix.cc',
+ 'native_library_win.cc',
+ 'observer_list.h',
+ 'observer_list_threadsafe.h',
+ 'os_compat_android.cc',
+ 'os_compat_android.h',
+ 'os_compat_nacl.cc',
+ 'os_compat_nacl.h',
+ 'path_service.cc',
+ 'path_service.h',
+ 'pending_task.cc',
+ 'pending_task.h',
+ 'pickle.cc',
+ 'pickle.h',
+ 'platform_file.cc',
+ 'platform_file.h',
+ 'platform_file_posix.cc',
+ 'platform_file_win.cc',
+ 'port.h',
+ 'posix/eintr_wrapper.h',
+ 'posix/global_descriptors.cc',
+ 'posix/global_descriptors.h',
+ 'posix/unix_domain_socket.cc',
+ 'posix/unix_domain_socket.h',
+ 'process.h',
+ 'process_info.h',
+ 'process_info_mac.cc',
+ 'process_info_win.cc',
+ 'process_linux.cc',
+ 'process_posix.cc',
+ 'process_util.cc',
+ 'process_util.h',
+ 'process_util_freebsd.cc',
+ 'process_util_ios.mm',
+ 'process_util_linux.cc',
+ 'process_util_mac.mm',
+ 'process_util_openbsd.cc',
+ 'process_util_posix.cc',
+ 'process_util_win.cc',
+ 'process_win.cc',
+ 'profiler/scoped_profile.cc',
+ 'profiler/scoped_profile.h',
+ 'profiler/alternate_timer.cc',
+ 'profiler/alternate_timer.h',
+ 'profiler/tracked_time.cc',
+ 'profiler/tracked_time.h',
+ 'rand_util.cc',
+ 'rand_util.h',
+ 'rand_util_nacl.cc',
+ 'rand_util_posix.cc',
+ 'rand_util_win.cc',
+ 'run_loop.cc',
+ 'run_loop.h',
+ 'safe_strerror_posix.cc',
+ 'safe_strerror_posix.h',
+ 'scoped_native_library.cc',
+ 'scoped_native_library.h',
+ 'sequenced_task_runner.cc',
+ 'sequenced_task_runner.h',
+ 'sequenced_task_runner_helpers.h',
+ 'sha1.h',
+ 'sha1_portable.cc',
+ 'sha1_win.cc',
+ 'shared_memory.h',
+ 'shared_memory_android.cc',
+ 'shared_memory_nacl.cc',
+ 'shared_memory_posix.cc',
+ 'shared_memory_win.cc',
+ 'single_thread_task_runner.h',
+ 'stl_util.h',
+ 'string_number_conversions.cc',
+ 'string_number_conversions.h',
+ 'string_piece.cc',
+ 'string_piece.h',
+ 'string_split.cc',
+ 'string_split.h',
+ 'string_tokenizer.h',
+ 'string_util.cc',
+ 'string_util.h',
+ 'string_util_posix.h',
+ 'string_util_win.h',
+ 'string16.cc',
+ 'string16.h',
+ 'stringize_macros.h',
+ 'stringprintf.cc',
+ 'stringprintf.h',
+ 'supports_user_data.cc',
+ 'supports_user_data.h',
+ 'synchronization/cancellation_flag.cc',
+ 'synchronization/cancellation_flag.h',
+ 'synchronization/condition_variable.h',
+ 'synchronization/condition_variable_posix.cc',
+ 'synchronization/condition_variable_win.cc',
+ 'synchronization/lock.cc',
+ 'synchronization/lock.h',
+ 'synchronization/lock_impl.h',
+ 'synchronization/lock_impl_posix.cc',
+ 'synchronization/lock_impl_win.cc',
+ 'synchronization/waitable_event.h',
+ 'synchronization/waitable_event_posix.cc',
+ 'synchronization/waitable_event_watcher.h',
+ 'synchronization/waitable_event_watcher_posix.cc',
+ 'synchronization/waitable_event_watcher_win.cc',
+ 'synchronization/waitable_event_win.cc',
+ 'system_monitor/system_monitor.cc',
+ 'system_monitor/system_monitor.h',
+ 'system_monitor/system_monitor_android.cc',
+ 'system_monitor/system_monitor_android.h',
+ 'system_monitor/system_monitor_ios.mm',
+ 'system_monitor/system_monitor_mac.mm',
+ 'system_monitor/system_monitor_posix.cc',
+ 'system_monitor/system_monitor_win.cc',
+ 'sys_byteorder.h',
+ 'sys_info.cc',
+ 'sys_info.h',
+ 'sys_info_android.cc',
+ 'sys_info_chromeos.cc',
+ 'sys_info_freebsd.cc',
+ 'sys_info_ios.mm',
+ 'sys_info_linux.cc',
+ 'sys_info_mac.cc',
+ 'sys_info_openbsd.cc',
+ 'sys_info_posix.cc',
+ 'sys_info_win.cc',
+ 'sys_string_conversions.h',
+ 'sys_string_conversions_mac.mm',
+ 'sys_string_conversions_posix.cc',
+ 'sys_string_conversions_win.cc',
+ 'task_runner.cc',
+ 'task_runner.h',
+ 'task_runner_util.h',
+ 'template_util.h',
+ 'thread_task_runner_handle.cc',
+ 'thread_task_runner_handle.h',
+ 'threading/non_thread_safe.h',
+ 'threading/non_thread_safe_impl.cc',
+ 'threading/non_thread_safe_impl.h',
+ 'threading/platform_thread.h',
+ 'threading/platform_thread_mac.mm',
+ 'threading/platform_thread_posix.cc',
+ 'threading/platform_thread_win.cc',
+ 'threading/post_task_and_reply_impl.cc',
+ 'threading/post_task_and_reply_impl.h',
+ 'threading/sequenced_worker_pool.cc',
+ 'threading/sequenced_worker_pool.h',
+ 'threading/simple_thread.cc',
+ 'threading/simple_thread.h',
+ 'threading/thread.cc',
+ 'threading/thread.h',
+ 'threading/thread_checker.h',
+ 'threading/thread_checker_impl.cc',
+ 'threading/thread_checker_impl.h',
+ 'threading/thread_collision_warner.cc',
+ 'threading/thread_collision_warner.h',
+ 'threading/thread_local.h',
+ 'threading/thread_local_posix.cc',
+ 'threading/thread_local_storage.h',
+ 'threading/thread_local_storage_posix.cc',
+ 'threading/thread_local_storage_win.cc',
+ 'threading/thread_local_win.cc',
+ 'threading/thread_restrictions.h',
+ 'threading/thread_restrictions.cc',
+ 'threading/watchdog.cc',
+ 'threading/watchdog.h',
+ 'threading/worker_pool.h',
+ 'threading/worker_pool.cc',
+ 'threading/worker_pool_posix.cc',
+ 'threading/worker_pool_posix.h',
+ 'threading/worker_pool_win.cc',
+ 'time.cc',
+ 'time.h',
+ 'time_mac.cc',
+ 'time_posix.cc',
+ 'time_win.cc',
+ 'timer.cc',
+ 'timer.h',
+ 'tracked_objects.cc',
+ 'tracked_objects.h',
+ 'tracking_info.cc',
+ 'tracking_info.h',
+ 'tuple.h',
+ 'utf_offset_string_conversions.cc',
+ 'utf_offset_string_conversions.h',
+ 'utf_string_conversion_utils.cc',
+ 'utf_string_conversion_utils.h',
+ 'utf_string_conversions.cc',
+ 'utf_string_conversions.h',
+ 'values.cc',
+ 'values.h',
+ 'value_conversions.cc',
+ 'value_conversions.h',
+ 'version.cc',
+ 'version.h',
+ 'vlog.cc',
+ 'vlog.h',
+ 'nix/mime_util_xdg.cc',
+ 'nix/mime_util_xdg.h',
+ 'nix/xdg_util.cc',
+ 'nix/xdg_util.h',
+ 'win/enum_variant.h',
+ 'win/enum_variant.cc',
+ 'win/event_trace_consumer.h',
+ 'win/event_trace_controller.cc',
+ 'win/event_trace_controller.h',
+ 'win/event_trace_provider.cc',
+ 'win/event_trace_provider.h',
+ 'win/i18n.cc',
+ 'win/i18n.h',
+ 'win/iat_patch_function.cc',
+ 'win/iat_patch_function.h',
+ 'win/iunknown_impl.h',
+ 'win/iunknown_impl.cc',
+ 'win/metro.cc',
+ 'win/metro.h',
+ 'win/object_watcher.cc',
+ 'win/object_watcher.h',
+ 'win/registry.cc',
+ 'win/registry.h',
+ 'win/resource_util.cc',
+ 'win/resource_util.h',
+ 'win/sampling_profiler.cc',
+ 'win/sampling_profiler.h',
+ 'win/scoped_bstr.cc',
+ 'win/scoped_bstr.h',
+ 'win/scoped_co_mem.h',
+ 'win/scoped_com_initializer.h',
+ 'win/scoped_comptr.h',
+ 'win/scoped_gdi_object.h',
+ 'win/scoped_handle.cc',
+ 'win/scoped_handle.h',
+ 'win/scoped_hdc.h',
+ 'win/scoped_hglobal.h',
+ 'win/scoped_process_information.cc',
+ 'win/scoped_process_information.h',
+ 'win/scoped_select_object.h',
+ 'win/shortcut.cc',
+ 'win/shortcut.h',
+ 'win/startup_information.cc',
+ 'win/startup_information.h',
+ 'win/scoped_variant.cc',
+ 'win/scoped_variant.h',
+ 'win/text_services_message_filter.cc',
+ 'win/text_services_message_filter.h',
+ 'win/windows_version.cc',
+ 'win/windows_version.h',
+ 'win/win_util.cc',
+ 'win/win_util.h',
+ 'win/wrapped_window_proc.cc',
+ 'win/wrapped_window_proc.h',
+ ],
+ 'defines': [
+ 'BASE_IMPLEMENTATION',
+ ],
+ 'include_dirs': [
+ '..',
+ ],
+ 'msvs_disabled_warnings': [
+ 4018,
+ ],
+ 'conditions': [
+ ['OS=="lb_shell"', {
+ 'sources': [
+ 'base_paths_shell.cc',
+ 'circular_buffer_shell.h',
+ 'circular_buffer_shell.cc',
+ 'message_pump_shell.cc',
+ 'message_pump_shell.h',
+ 'native_library_shell.cc', # Stub implementation
+ 'object_watcher_shell.cc',
+ 'object_watcher_shell.h',
+ 'optional.cc',
+ 'optional.h',
+ 'optional_internal.h',
+ 'shared_memory_shell.cc', # Stub implementation
+ 'state_machine_shell.h',
+ 'state_machine_shell.cc',
+ 'synchronization/condition_variable_shell.cc',
+ 'synchronization/lock_impl_shell.cc',
+ 'synchronization/waitable_event_shell.cc',
+ 'threading/thread_checker_impl_atomic.cc',
+ '<!@(find <(lbshell_root)/src/platform/<(target_arch)/chromium/base -type f)',
+ ],
+ 'sources!': [
+ 'threading/thread_checker_impl.cc',
+ ],
+ 'sources/': [
+ ['include', 'sys_string_conversions_linux.cc'],
+ ],
+ }],
+ [ 'OS=="lb_shell" and target_arch!="linux" and target_arch!="android"', {
+ 'sources!': [
+ 'string16.cc', # wchar_t is 2-bytes wide, string16 == wstring here.
+ ],
+ }],
+ [ 'OS=="lb_shell" and target_arch=="android"', {
+ 'sources/' : [
+ ['exclude', 'message_pump_shell.cc'],
+ ['exclude', 'message_pump_shell.h'],
+ ['exclude', 'native_library_shell.cc'],
+ ['exclude', 'process_util.cc'],
+ ['exclude', '<(lbshell_root)/src/object_watcher_shell.cc'],
+ ['exclude', '<(lbshell_root)/src/object_watcher_shell.h'],
+ ['include', 'message_pump_libevent.cc'],
+ ['include', 'message_pump_libevent.h'],
+ ['include', 'native_library_posix.cc'],
+ ],
+ }],
+ # For Starboard, we are going to build this back up as necessary.
+ ['OS=="starboard"', {
+ 'sources': [
+ 'base_paths_starboard.cc',
+ 'circular_buffer_shell.cc',
+ 'circular_buffer_shell.h',
+ 'debug/debugger_starboard.cc',
+ 'debug/stack_trace_starboard.cc',
+ 'file_util_starboard.cc',
+ 'guid_starboard.cc',
+ 'message_pump_io_starboard.cc',
+ 'message_pump_io_starboard.h',
+ 'message_pump_ui_starboard.cc',
+ 'message_pump_ui_starboard.h',
+ 'optional.cc',
+ 'optional.h',
+ 'optional_internal.h',
+ 'platform_file_starboard.cc',
+ 'process_starboard.cc',
+ 'process_util_starboard.cc',
+ 'rand_util_starboard.cc',
+ 'state_machine_shell.cc',
+ 'state_machine_shell.h',
+ 'synchronization/condition_variable_starboard.cc',
+ 'synchronization/lock_impl_starboard.cc',
+ 'synchronization/waitable_event_starboard.cc',
+ 'sys_info_starboard.cc',
+ 'sys_string_conversions_starboard.cc',
+ 'system_monitor/system_monitor_starboard.cc',
+ 'threading/platform_thread_starboard.cc',
+ 'threading/thread_checker_impl_atomic.cc',
+ 'threading/thread_local_starboard.cc',
+ 'threading/thread_local_storage_starboard.cc',
+ 'threading/worker_pool_starboard.cc',
+ 'time_starboard.cc',
+ ],
+ 'sources!': [
+ # Uses file_util::ReplaceFile, which isn't implemented in
+ # Starboard, and isn't otherwise used in Cobalt.
+ 'files/important_file_writer.cc',
+ 'files/important_file_writer.h',
+
+ # All the common functions have been removed for Starboard, so we
+ # don't even want to compile this.
+ 'process_util.cc',
+
+ # Tricky to support cross-platform, and not used by Cobalt.
+ 'scoped_native_library.cc',
+ 'scoped_native_library.h',
+
+ # We use thread_checker_impl_atomic.cc instead.
+ 'threading/thread_checker_impl.cc',
+ ],
+ 'conditions': [
+ ['target_os!="linux" and target_arch!="android"', {
+ 'sources!': [
+ # Since wchar_t is 2-bytes wide, string16 == wstring here.
+ 'string16.cc',
+ ],
+ }],
+ ],
+ }], # OS == "starboard"
+ [ 'OS=="lb_shell" or OS=="starboard"', {
+ 'sources!': [
+ 'environment.cc',
+ 'file_descriptor_shuffle.cc',
+ 'files/file_path_watcher.cc',
+ 'files/file_path_watcher_kqueue.cc',
+ 'files/file_path_watcher_stub.cc',
+ 'message_pump_libevent.cc',
+ 'message_pump_libevent.h',
+ 'metrics/stats_table.cc',
+ 'metrics/stats_table.h',
+ ],
+ }], # OS == "lb_shell" or OS == "starboard"
+ ],
+ 'target_conditions': [
+ ['<(use_glib)==0 or >(nacl_untrusted_build)==1', {
+ 'sources/': [
+ ['exclude', '^nix/'],
+ ],
+ 'sources!': [
+ 'atomicops_internals_x86_gcc.cc',
+ 'message_pump_glib.cc',
+ 'message_pump_aurax11.cc',
+ ],
+ }],
+ ['<(toolkit_uses_gtk)==0 or >(nacl_untrusted_build)==1', {
+ 'sources!': ['message_pump_gtk.cc'],
+ }],
+ ['(OS != "linux" and <(os_bsd) != 1 and OS != "android") or >(nacl_untrusted_build)==1', {
+ 'sources!': [
+ # Not automatically excluded by the *linux.cc rules.
+ 'linux_util.cc',
+ ],
+ },
+ ],
+ ['>(nacl_untrusted_build)==1', {
+ 'sources!': [
+ 'allocator/type_profiler_control.cc',
+ 'allocator/type_profiler_control.h',
+ 'base_paths.cc',
+ 'command_line.cc',
+ 'cpu.cc',
+ 'debug/stack_trace_posix.cc',
+ 'file_util.cc',
+ 'file_util_posix.cc',
+ 'file_util_proxy.cc',
+ 'files/file_path_watcher_kqueue.cc',
+ 'native_library_posix.cc',
+ 'path_service.cc',
+ 'platform_file_posix.cc',
+ 'posix/unix_domain_socket.cc',
+ 'process_posix.cc',
+ 'process_util.cc',
+ 'process_util_posix.cc',
+ 'rand_util_posix.cc',
+ 'scoped_native_library.cc',
+ 'files/scoped_temp_dir.cc',
+ 'shared_memory_posix.cc',
+ 'sys_info_posix.cc',
+ 'threading/sequenced_worker_pool.cc',
+ 'third_party/dynamic_annotations/dynamic_annotations.c',
+ ],
+ # Metrics won't work in the NaCl sandbox.
+ 'sources/': [ ['exclude', '^metrics/'] ],
+ }],
+ ['OS == "android" and >(nacl_untrusted_build)==0', {
+ 'sources!': [
+ 'base_paths_posix.cc',
+ 'files/file_path_watcher_kqueue.cc',
+ 'files/file_path_watcher_stub.cc',
+ 'system_monitor/system_monitor_posix.cc',
+ ],
+ 'sources/': [
+ ['include', '^files/file_path_watcher_linux\\.cc$'],
+ ['include', '^process_util_linux\\.cc$'],
+ ['include', '^sys_info_linux\\.cc$'],
+ ['include', '^sys_string_conversions_posix\\.cc$'],
+ ['include', '^worker_pool_linux\\.cc$'],
+ ],
+ }],
+ ['OS == "ios"', {
+ 'sources/': [
+ # Pull in specific Mac files for iOS (which have been filtered out
+ # by file name rules).
+ ['include', '^atomicops_internals_mac\\.'],
+ ['include', '^base_paths_mac\\.'],
+ ['include', '^file_util_mac\\.'],
+ ['include', '^file_version_info_mac\\.'],
+ ['include', '^mac/bind_objc_block\\.'],
+ ['include', '^mac/bundle_locations\\.'],
+ ['include', '^mac/foundation_util\\.'],
+ ['include', '^mac/mac_logging\\.'],
+ ['include', '^mac/objc_property_releaser\\.'],
+ ['include', '^mac/scoped_mach_port\\.'],
+ ['include', '^mac/scoped_nsautorelease_pool\\.'],
+ ['include', '^message_pump_mac\\.'],
+ ['include', '^threading/platform_thread_mac\\.'],
+ ['include', '^sys_string_conversions_mac\\.'],
+ ['include', '^time_mac\\.'],
+ ['include', '^worker_pool_mac\\.'],
+ # Exclude all process_util except the minimal implementation
+ # needed on iOS (mostly for unit tests).
+ ['exclude', '^process_util'],
+ ['include', '^process_util_ios\\.mm$'],
+ ],
+ 'sources!': [
+ 'message_pump_libevent.cc'
+ ],
+ }],
+ ['OS != "mac" or >(nacl_untrusted_build)==1', {
+ 'sources!': [
+ 'mac/scoped_aedesc.h'
+ ],
+ }],
+ # For now, just test the *BSD platforms enough to exclude them.
+ # Subsequent changes will include them further.
+ ['OS != "freebsd" or >(nacl_untrusted_build)==1', {
+ 'sources/': [ ['exclude', '_freebsd\\.cc$'] ],
+ },
+ ],
+ ['OS != "openbsd" or >(nacl_untrusted_build)==1', {
+ 'sources/': [ ['exclude', '_openbsd\\.cc$'] ],
+ },
+ ],
+ ['OS != "win" or >(nacl_untrusted_build)==1', {
+ 'sources/': [ ['exclude', '^win/'] ],
+ },
+ ],
+ ['(OS != "android" or >(nacl_untrusted_build)==1) and (OS != "lb_shell" or "<(target_arch)" != "android")', {
+ 'sources/': [ ['exclude', '^android/'] ],
+ },
+ ],
+ ['OS == "win" and >(nacl_untrusted_build)==0', {
+ 'include_dirs': [
+ '<(DEPTH)/third_party/wtl/include',
+ ],
+ 'sources!': [
+ 'event_recorder_stubs.cc',
+ 'files/file_path_watcher_kqueue.cc',
+ 'files/file_path_watcher_stub.cc',
+ 'message_pump_libevent.cc',
+ 'posix/file_descriptor_shuffle.cc',
+ # Not using sha1_win.cc because it may have caused a
+ # regression to page cycler moz.
+ 'sha1_win.cc',
+ 'string16.cc',
+ ],
+ },],
+ ['OS == "linux" and >(nacl_untrusted_build)==0', {
+ 'sources!': [
+ 'files/file_path_watcher_kqueue.cc',
+ 'files/file_path_watcher_stub.cc',
+ ],
+ }],
+ ['(OS == "mac" or OS == "ios") and >(nacl_untrusted_build)==0', {
+ 'sources/': [
+ ['exclude', '^files/file_path_watcher_stub\\.cc$'],
+ ['exclude', '^base_paths_posix\\.cc$'],
+ ['exclude', '^native_library_posix\\.cc$'],
+ ['exclude', '^sys_string_conversions_posix\\.cc$'],
+ ],
+ }],
+ ['<(os_bsd)==1 and >(nacl_untrusted_build)==0', {
+ 'sources/': [
+ ['exclude', '^files/file_path_watcher_linux\\.cc$'],
+ ['exclude', '^files/file_path_watcher_stub\\.cc$'],
+ ['exclude', '^file_util_linux\\.cc$'],
+ ['exclude', '^process_linux\\.cc$'],
+ ['exclude', '^process_util_linux\\.cc$'],
+ ['exclude', '^sys_info_linux\\.cc$'],
+ ],
+ }],
+ ['<(chromeos)!=1 or >(nacl_untrusted_build)==1', {
+ 'sources/': [
+ ['exclude', '^chromeos/'],
+ ],
+ }],
+ # Remove all unnecessary files for build_nexe.py to avoid exceeding
+ # command-line-string limitation when building NaCl on Windows.
+ ['OS == "win" and >(nacl_untrusted_build)==1', {
+ 'sources/': [ ['exclude', '\\.h$'] ],
+ }],
+ ],
+ }],
+ ],
+ },
+}
diff --git a/src/base/base64.cc b/src/base/base64.cc
new file mode 100644
index 0000000..1907978
--- /dev/null
+++ b/src/base/base64.cc
@@ -0,0 +1,43 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/base64.h"
+
+#include "third_party/modp_b64/modp_b64.h"
+
+namespace base {
+
+bool Base64Encode(const StringPiece& input, std::string* output) {
+ std::string temp;
+ temp.resize(modp_b64_encode_len(input.size())); // makes room for null byte
+
+ // null terminates result since result is base64 text!
+ int input_size = static_cast<int>(input.size());
+
+ // modp_b64_encode_len() returns at least 1, so temp[0] is safe to use.
+ int output_size = modp_b64_encode(&(temp[0]), input.data(), input_size);
+ if (output_size < 0)
+ return false;
+
+ temp.resize(output_size); // strips off null byte
+ output->swap(temp);
+ return true;
+}
+
+bool Base64Decode(const StringPiece& input, std::string* output) {
+ std::string temp;
+ temp.resize(modp_b64_decode_len(input.size()));
+
+ // does not null terminate result since result is binary data!
+ int input_size = static_cast<int>(input.size());
+ int output_size = modp_b64_decode(&(temp[0]), input.data(), input_size);
+ if (output_size < 0)
+ return false;
+
+ temp.resize(output_size);
+ output->swap(temp);
+ return true;
+}
+
+} // namespace base
diff --git a/src/base/base64.h b/src/base/base64.h
new file mode 100644
index 0000000..983d5e2
--- /dev/null
+++ b/src/base/base64.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BASE64_H__
+#define BASE_BASE64_H__
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/string_piece.h"
+
+namespace base {
+
+// Encodes the input string in base64. Returns true if successful and false
+// otherwise. The output string is only modified if successful.
+BASE_EXPORT bool Base64Encode(const StringPiece& input, std::string* output);
+
+// Decodes the base64 input string. Returns true if successful and false
+// otherwise. The output string is only modified if successful.
+BASE_EXPORT bool Base64Decode(const StringPiece& input, std::string* output);
+
+} // namespace base
+
+#endif // BASE_BASE64_H__
diff --git a/src/base/base64_unittest.cc b/src/base/base64_unittest.cc
new file mode 100644
index 0000000..9a5dd81
--- /dev/null
+++ b/src/base/base64_unittest.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/base64.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(Base64Test, Basic) {
+ const std::string kText = "hello world";
+ const std::string kBase64Text = "aGVsbG8gd29ybGQ=";
+
+ std::string encoded;
+ std::string decoded;
+ bool ok;
+
+ ok = Base64Encode(kText, &encoded);
+ EXPECT_TRUE(ok);
+ EXPECT_EQ(kBase64Text, encoded);
+
+ ok = Base64Decode(encoded, &decoded);
+ EXPECT_TRUE(ok);
+ EXPECT_EQ(kText, decoded);
+}
+
+} // namespace base
diff --git a/src/base/base_export.h b/src/base/base_export.h
new file mode 100644
index 0000000..fdfa5f9
--- /dev/null
+++ b/src/base/base_export.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BASE_EXPORT_H_
+#define BASE_BASE_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(_MSC_VER)
+#if defined(BASE_IMPLEMENTATION)
+#define BASE_EXPORT __declspec(dllexport)
+#define BASE_EXPORT_PRIVATE __declspec(dllexport)
+#else
+#define BASE_EXPORT __declspec(dllimport)
+#define BASE_EXPORT_PRIVATE __declspec(dllimport)
+#endif // defined(BASE_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(BASE_IMPLEMENTATION)
+#define BASE_EXPORT __attribute__((visibility("default")))
+#define BASE_EXPORT_PRIVATE __attribute__((visibility("default")))
+#else
+#define BASE_EXPORT
+#define BASE_EXPORT_PRIVATE
+#endif // defined(BASE_IMPLEMENTATION)
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define BASE_EXPORT
+#define BASE_EXPORT_PRIVATE
+#endif
+
+#endif // BASE_BASE_EXPORT_H_
diff --git a/src/base/base_paths.cc b/src/base/base_paths.cc
new file mode 100644
index 0000000..80105b6
--- /dev/null
+++ b/src/base/base_paths.cc
@@ -0,0 +1,38 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/base_paths.h"
+
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+
+namespace base {
+
+bool PathProvider(int key, FilePath* result) {
+ // NOTE: DIR_CURRENT is a special case in PathService::Get
+
+ FilePath cur;
+ switch (key) {
+ case base::DIR_EXE:
+ PathService::Get(base::FILE_EXE, &cur);
+ cur = cur.DirName();
+ break;
+ case base::DIR_MODULE:
+ PathService::Get(base::FILE_MODULE, &cur);
+ cur = cur.DirName();
+ break;
+ case base::DIR_TEMP:
+ if (!file_util::GetTempDir(&cur))
+ return false;
+ break;
+ default:
+ return false;
+ }
+
+ *result = cur;
+ return true;
+}
+
+} // namespace base
diff --git a/src/base/base_paths.h b/src/base/base_paths.h
new file mode 100644
index 0000000..7bc23a8
--- /dev/null
+++ b/src/base/base_paths.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BASE_PATHS_H_
+#define BASE_BASE_PATHS_H_
+
+// This file declares path keys for the base module. These can be used with
+// the PathService to access various special directories and files.
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/base_paths_win.h"
+#elif defined(OS_MACOSX)
+#include "base/base_paths_mac.h"
+#elif defined(OS_ANDROID) || defined(__LB_ANDROID__)
+#include "base/base_paths_android.h"
+#elif defined(OS_STARBOARD)
+#include "base/base_paths_starboard.h"
+#endif
+
+#if defined(OS_POSIX)
+#include "base/base_paths_posix.h"
+#endif
+
+namespace base {
+