Reverting patch on wrong branch.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@668 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
lrn@chromium.org 2008-10-31 10:19:01 +00:00
parent 2a6c90e668
commit 2da0c25569
580 changed files with 0 additions and 209265 deletions

View File

@ -1,13 +0,0 @@
# Below is a list of people and organizations that have contributed
# to the V8 project. Names should be added to the list like so:
#
# Name/Organization <email address>
Google Inc.
Rene Rebe <rene@exactcode.de>
Rafal Krypa <rafal@krypa.net>
Jay Freeman <saurik@saurik.com>
Daniel James <dnljms@gmail.com>
Paolo Giarrusso <p.giarrusso@gmail.com>
Daniel Andersson <kodandersson@gmail.com>

View File

@ -1,403 +0,0 @@
2008-10-23: Version 0.4.0
Split the global object into two parts: The state holding global
object and the global object proxy.
Fixed bug that affected the value of an assignment to an element
in certain cases (issue 116).
Added GetPropertyNames functionality (issue 33) and extra Date
functions (issue 77) to the API.
Changed WeakReferenceCallback to take a Persistent<Value> instead
of a Persistent<Object> (issue 101).
Fixed issues with message reporting for exceptions in try-finally
blocks (issues 73 and 75).
Optimized flattening of strings and string equality checking.
Improved Boyer-Moore implementation for faster indexOf operations.
Added development shell (d8) which includes counters and
completion support.
Fixed problem with the receiver passed to functions called from
eval (issue 124).
2008-10-16: Version 0.3.5
Improved string hash-code distribution by excluding bit-field bits
from the hash-code.
Changed string search algorithm used in indexOf from KMP to
Boyer-Moore.
Improved the generated code for the instanceof operator.
Improved performance of slow-case string equality checks by
specializing the code based on the string representation.
Improve the handling of out-of-memory situations (issue 70).
Improved performance of strict equality checks.
Improved profiler output to make it easier to see anonymous
functions.
Improved performance of slow-case keyed loads.
Improved property access performance by allocating a number of
properties in the front object.
Changed the toString behavior on the built-in object constructors
to print [native code] instead of the actual source. Some web
applications do not like constructors with complex toString
results.
2008-10-06: Version 0.3.4
Changed Array.prototype.sort to use quick sort.
Fixed code generation issue where leaving a finally block with
break or continue would accumulate elements on the expression
stack (issue 86).
Made sure that the name accessor on functions returns the expected
names for builtin JavaScript functions and C++ callback functions.
Added fast case code for extending the property storage array of
JavaScript objects.
Ported switch statement optimizations introduced in version 0.3.3
to the ARM code generator.
Allowed GCC to use strict-aliasing rules when compiling.
Improved performance of arguments object allocation by taking care
of arguments adaptor frames in the generated code.
Updated the V8 benchmark suite to version 2.
2008-09-25: Version 0.3.3
Improved handling of relocation information to enable more
peep-hole optimizations.
Optimized switch statements where all labels are constant small
integers.
Optimized String.prototype.indexOf for common cases.
Fixed more build issues (issue 80).
Fixed a couple of profiler issues.
Fixed bug where the body of a function created using the Function
constructor was not allowed to end with a single-line comment
(issue 85).
Improved handling of object literals by canonicalizing object
literal maps. This will allow JSON objects with the same set of
properties to share the same map making inline caching work better
for JSON objects.
2008-09-17: Version 0.3.2
Generalized the EvalCache into a CompilationCache and enabled it
for scripts too. The current strategy is to retire all entries
whenever a mark-sweep collection is started.
Fixed bug where switch statements containing only a default case
would lead to an unbalanced stack (issue 69).
Fixed bug that made access to the function in a named function
expression impossible in certain situations (issue 24).
Fixed even more build issues.
Optimized calling conventions on ARM. The conventions on ARM and
IA-32 now match.
Removed static initializers for flags and counters.
Improved inline caching behavior for uncommon cases where lazily
loading Date and RegExp code could force certain code paths go
megamorphic.
Removed arguments adaption for builtins written in C++. This
makes Array.prototype.push and Array.prototype.pop slightly
faster.
2008-09-11: Version 0.3.1
Fixed a number of build issues.
Fixed problem with missing I-cache flusing on ARM.
Changed space layout in memory management by splitting up
code space into old data space and code space.
Added utf-8 conversion support to the API (issue 57).
Optimized repeated calls to eval with the same strings. These
repeated calls are common in web applications.
Added Xcode project file.
Optimized a couple of Array operation.
Fixed parser bug by checking for end-of-string when parsing break
and continue (issue 35).
Fixed problem where asian characters were not categorized as
letters.
Fixed bug that disallowed calling functions fetched from an array
using a string as an array index (issue 32).
Fixed bug where the internal field count on object templates were
sometimes ignored (issue 54).
Added -f option to the shell sample for compatibility with other
engines (issue 18).
Added source info to TryCatches in the API.
Fixed problem where the seed for the random number generator was
clipped in a double to unsigned int conversion.
Fixed bug where cons string symbols were sometimes converted to
non-symbol flat strings during GC.
Fixed bug in error reporting when attempting to convert null to an
object.
2008-09-04: Version 0.3.0
Added support for running tests on the ARM simulator.
Fixed bug in the 'in' operator where negative indices were not
treated correctly.
Fixed build issues on gcc-4.3.1.
Changed Date.prototype.toLocaleTimeString to not print the
timezone part of the time.
Renamed debug.h to v8-debug.h to reduce the risk of name conflicts
with user code.
2008-09-02: Version 0.2.5
Renamed the top level directory 'public' to 'include'.
Added 'env' option to the SCons build scripts to support
overriding the ENV part of the build environment. This is mostly
to support Windows builds in cases where SCons cannot find the
correct paths to the Windows SDK, as these paths cannot be passed
through shell environment variables.
Enabled "Buffer Security Check" on for the Windows SCons build and
added the linker option /OPT:ICF as an optimization.
Added the V8 benchmark suite to the repository.
2008-09-01: Version 0.2.4
Included mjsunit JavaScript test suite and C++ unit tests.
Changed the shell sample to not print the result of executing a
script provided on the command line.
Fixed issue when building samples on Windows using a shared V8
library. Added visibility option on Linux build which makes the
generated library 18% smaller.
Changed build system to accept multiple build modes in one build
and generate separate objects, libraries and executables for each
mode.
Removed deferred negation optimization (a * -b => -(a * b)) since
this visibly changes operand conversion order.
Improved parsing performance by introducing stack guard in
preparsing. Without a stack guard preparsing always bails out
with stack overflow.
Changed shell sample to take flags directly from the command-line.
Added API call that implements this.
Added load, quit and version functions to the shell sample so it's
easier to run benchmarks and tests.
Fixed issue with building samples and cctests on 64-bit machines.
Fixed bug in the runtime system where the prototype chain was not
always searched for a setter when setting a property that does not
exist locally.
2008-08-14: Version 0.2.3
Improved performance of garbage collection by moving the
function that updates pointers during compacting collection
into the updating visitor. This gives the compiler a better
chance to inline and avoid a function call per (potential)
pointer.
Extended the shell sample with a --runtime-flags option.
Added Visual Studio project files for the shell.cc and
process.cc samples.
2008-08-13: Version 0.2.2
Improved performance of garbage collection by changing the way
we use the marking stack in the event of stack overflow during
full garbage collection and by changing the way we mark roots.
Cleaned up ARM version by removing top of stack caching and by
introducing push/pop elimination.
Cleaned up the way runtime functions are called to allow
runtime calls with no arguments.
Changed Windows build options to make sure that exceptions are
disabled and that optimization flags are enabled.
Added first version of Visual Studio project files.
2008-08-06: Version 0.2.1
Improved performance of unary addition by avoiding runtime calls.
Fixed the handling of '>' and '<=' to use right-to-left conversion
and left-to-right evaluation as specified by ECMA-262.
Fixed a branch elimination bug on the ARM platform where incorrect
code was generated because of overly aggressive branch
elimination.
Improved performance of code that repeatedly assigns the same
function to the same property of different objects with the same
map.
Untangled DEBUG and ENABLE_DISASSEMBLER defines. The disassembler
no longer expects DEBUG to be defined.
Added platform-nullos.cc to serve as the basis for new platform
implementations.
2008-07-30: Version 0.2.0
Changed all text files to have native svn:eol-style.
Added a few samples and support for building them. The samples
include a simple shell that can be used to benchmark and test V8.
Changed V8::GetVersion to return the version as a string.
Added source for lazily loaded scripts to snapshots and made
serialization non-destructive.
Improved ARM support by fixing the write barrier code to use
aligned loads and stores and by removing premature locals
optimization that relied on broken support for callee-saved
registers (removed).
Refactored the code for marking live objects during garbage
collection and the code for allocating objects in paged
spaces. Introduced an abstraction for the map word of a heap-
allocated object and changed the memory allocator to allocate
executable memory only for spaces that may contain code objects.
Moved StringBuilder to utils.h and ScopedLock to platform.h, where
they can be used by debugging and logging modules. Added
thread-safe message queues for dealing with debugger events.
Fixed the source code reported by toString for certain builtin
empty functions and made sure that the prototype property of a
function is enumerable.
Improved performance of converting values to condition flags in
generated code.
Merged disassembler-{arch} files.
2008-07-28: Version 0.1.4
Added support for storing JavaScript stack traces in a stack
allocated buffer to make it visible in shallow core dumps.
Controlled by the --preallocate-message-memory flag which is
disabled by default.
2008-07-25: Version 0.1.3
Fixed bug in JSObject::GetPropertyAttributePostInterceptor where
map transitions would count as properties.
Allowed aliased eval invocations by treating them as evals in the
global context. This may change in the future.
Added support for accessing the last entered context through the
API and renamed Context::Current to Context::GetCurrent and
Context::GetSecurityContext to Context::GetCurrentSecurityContext.
Fixed bug in the debugger that would cause the debugger scripts to
be recursively loaded and changed all disabling of interrupts to
be block-structured.
Made snapshot data read-only to allow it to be more easily shared
across multiple users of V8 when linked as a shared library.
2008-07-16: Version 0.1.2
Fixed building on Mac OS X by recognizing i386 and friends as
IA-32 platforms.
Added propagation of stack overflow exceptions that occur while
compiling nested functions.
Improved debugger with support for recursive break points and
handling of exceptions that occur in the debugger JavaScript code.
Renamed GetInternal to GetInternalField and SetInternal to
SetInternalField in the API and moved InternalFieldCount and
SetInternalFieldCount from FunctionTemplate to ObjectTemplate.
2008-07-09: Version 0.1.1
Fixed bug in stack overflow check code for IA-32 targets where a
non-tagged value in register eax was pushed to the stack.
Fixed potential quadratic behavior when converting strings to
numbers.
Fixed bug where the return value from Object::SetProperty could
end up being the property holder instead of the written value.
Improved debugger support by allowing nested break points and by
dealing with stack-overflows when compiling functions before
setting break points in them.
2008-07-03: Version 0.1.0
Initial export.

View File

@ -1,46 +0,0 @@
This license applies to all parts of V8 that are not externally
maintained libraries. The externally maintained libraries used by V8
are:
- Jscre, located under third_party/jscre. This code is copyrighted
by the University of Cambridge and Apple Inc. and released under a
2-clause BSD license.
- Dtoa, located under third_party/dtoa. This code is copyrighted by
David M. Gay and released under an MIT license.
- Strongtalk assembler, the basis of the files assembler-arm-inl.h,
assembler-arm.cc, assembler-arm.h, assembler-ia32-inl.h,
assembler-ia32.cc, assembler-ia32.h, assembler.cc and assembler.h.
This code is copyrighted by Sun Microsystems Inc. and released
under a 3-clause BSD license.
These libraries have their own licenses; we recommend you read them,
as their terms may differ from the terms below.
Copyright 2006-2008, Google Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of 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.

View File

@ -1,578 +0,0 @@
# Copyright 2008 the V8 project 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.
import platform
import re
import sys
import os
from os.path import join, dirname, abspath
from types import DictType, StringTypes
root_dir = dirname(File('SConstruct').rfile().abspath)
sys.path.append(join(root_dir, 'tools'))
import js2c, utils
LIBRARY_FLAGS = {
'all': {
'CPPDEFINES': ['ENABLE_LOGGING_AND_PROFILING']
},
'gcc': {
'all': {
'DIALECTFLAGS': ['-ansi'],
'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS'],
'CXXFLAGS': ['$CCFLAGS', '-fno-rtti', '-fno-exceptions'],
'LIBS': ['pthread']
},
'mode:debug': {
'CCFLAGS': ['-g', '-O0'],
'CPPDEFINES': ['ENABLE_DISASSEMBLER', 'DEBUG']
},
'mode:release': {
'CCFLAGS': ['-O3', '-fomit-frame-pointer']
},
'wordsize:64': {
'CCFLAGS': ['-m32'],
'LINKFLAGS': ['-m32']
}
},
'msvc': {
'all': {
'DIALECTFLAGS': ['/nologo'],
'CCFLAGS': ['$DIALECTFLAGS', '$WARNINGFLAGS'],
'CXXFLAGS': ['$CCFLAGS', '/GR-', '/Gy'],
'CPPDEFINES': ['WIN32', '_USE_32BIT_TIME_T', 'PCRE_STATIC'],
'LINKFLAGS': ['/NOLOGO', '/MACHINE:X86', '/INCREMENTAL:NO',
'/NXCOMPAT', '/IGNORE:4221'],
'ARFLAGS': ['/NOLOGO'],
'CCPDBFLAGS': ['/Zi']
},
'mode:debug': {
'CCFLAGS': ['/Od', '/Gm', '/MTd'],
'CPPDEFINES': ['_DEBUG', 'ENABLE_DISASSEMBLER', 'DEBUG'],
'LINKFLAGS': ['/DEBUG']
},
'mode:release': {
'CCFLAGS': ['/O2', '/MT', '/GL'],
'LINKFLAGS': ['/OPT:REF', '/OPT:ICF', '/LTCG'],
'ARFLAGS': ['/LTCG']
}
}
}
V8_EXTRA_FLAGS = {
'gcc': {
'all': {
'CXXFLAGS': [], #['-fvisibility=hidden'],
'WARNINGFLAGS': ['-pedantic', '-Wall', '-Werror', '-W',
'-Wno-unused-parameter']
},
'arch:arm': {
'CPPDEFINES': ['ARM']
},
'disassembler:on': {
'CPPDEFINES': ['ENABLE_DISASSEMBLER']
}
},
'msvc': {
'all': {
'WARNINGFLAGS': ['/W3', '/WX', '/wd4355', '/wd4800']
},
'library:shared': {
'CPPDEFINES': ['BUILDING_V8_SHARED']
},
'arch:arm': {
'CPPDEFINES': ['ARM']
},
'disassembler:on': {
'CPPDEFINES': ['ENABLE_DISASSEMBLER']
}
}
}
JSCRE_EXTRA_FLAGS = {
'gcc': {
'all': {
'CPPDEFINES': ['SUPPORT_UTF8', 'NO_RECURSE', 'SUPPORT_UCP'],
'WARNINGFLAGS': ['-w']
},
},
'msvc': {
'all': {
'CPPDEFINES': ['SUPPORT_UTF8', 'NO_RECURSE', 'SUPPORT_UCP'],
'WARNINGFLAGS': ['/W3', '/WX', '/wd4355', '/wd4800']
},
'library:shared': {
'CPPDEFINES': ['BUILDING_V8_SHARED']
}
}
}
DTOA_EXTRA_FLAGS = {
'gcc': {
'all': {
'WARNINGFLAGS': ['-Werror']
}
},
'msvc': {
'all': {
'WARNINGFLAGS': ['/WX', '/wd4018', '/wd4244']
}
}
}
CCTEST_EXTRA_FLAGS = {
'all': {
'CPPPATH': [join(root_dir, 'src')],
'LIBS': ['$LIBRARY']
},
'gcc': {
'all': {
'LIBPATH': [abspath('.')]
},
'wordsize:64': {
'CCFLAGS': ['-m32'],
'LINKFLAGS': ['-m32']
},
},
'msvc': {
'all': {
'CPPDEFINES': ['_HAS_EXCEPTIONS=0']
},
'library:shared': {
'CPPDEFINES': ['USING_V8_SHARED']
}
}
}
SAMPLE_FLAGS = {
'all': {
'CPPPATH': [join(abspath('.'), 'include')],
'LIBS': ['$LIBRARY'],
},
'gcc': {
'all': {
'LIBS': ['pthread'],
'LIBPATH': ['.']
},
'wordsize:64': {
'CCFLAGS': ['-m32'],
'LINKFLAGS': ['-m32']
},
'mode:release': {
'CCFLAGS': ['-O2']
},
'mode:debug': {
'CCFLAGS': ['-g', '-O0']
}
},
'msvc': {
'all': {
'CCFLAGS': ['/nologo'],
'LINKFLAGS': ['/nologo'],
},
'library:shared': {
'CPPDEFINES': ['USING_V8_SHARED']
},
'prof:on': {
'LINKFLAGS': ['/MAP']
},
'mode:release': {
'CCFLAGS': ['/O2', '/MT'],
'LINKFLAGS': ['/OPT:REF', '/OPT:ICF', '/LTCG']
},
'mode:debug': {
'CCFLAGS': ['/Od', '/MTd'],
'LINKFLAGS': ['/DEBUG']
}
}
}
D8_FLAGS = {
'gcc': {
'console:readline': {
'LIBS': ['readline']
}
},
'msvc': { }
}
SUFFIXES = {
'release': '',
'debug': '_g'
}
def Abort(message):
print message
sys.exit(1)
def GuessOS():
id = platform.system()
if id == 'Linux':
return 'linux'
elif id == 'Darwin':
return 'macos'
elif id == 'Windows':
return 'win32'
else:
return None
def GuessWordsize():
if '64' in platform.machine():
return '64'
else:
return '32'
def GuessToolchain(os):
tools = Environment()['TOOLS']
if 'gcc' in tools:
return 'gcc'
elif 'msvc' in tools:
return 'msvc'
else:
return None
OS_GUESS = GuessOS()
TOOLCHAIN_GUESS = GuessToolchain(OS_GUESS)
ARCH_GUESS = utils.GuessArchitecture()
WORDSIZE_GUESS = GuessWordsize()
SIMPLE_OPTIONS = {
'toolchain': {
'values': ['gcc', 'msvc'],
'default': TOOLCHAIN_GUESS,
'help': 'the toolchain to use'
},
'os': {
'values': ['linux', 'macos', 'win32'],
'default': OS_GUESS,
'help': 'the os to build for'
},
'arch': {
'values':['arm', 'ia32'],
'default': ARCH_GUESS,
'help': 'the architecture to build for'
},
'snapshot': {
'values': ['on', 'off'],
'default': 'off',
'help': 'build using snapshots for faster start-up'
},
'prof': {
'values': ['on', 'off'],
'default': 'off',
'help': 'enable profiling of build target'
},
'library': {
'values': ['static', 'shared'],
'default': 'static',
'help': 'the type of library to produce'
},
'wordsize': {
'values': ['64', '32'],
'default': WORDSIZE_GUESS,
'help': 'the word size'
},
'simulator': {
'values': ['arm', 'none'],
'default': 'none',
'help': 'build with simulator'
},
'disassembler': {
'values': ['on', 'off'],
'default': 'off',
'help': 'enable the disassembler to inspect generated code'
},
'sourcesignatures': {
'values': ['MD5', 'timestamp'],
'default': 'MD5',
'help': 'set how the build system detects file changes'
},
'console': {
'values': ['dumb', 'readline'],
'default': 'dumb',
'help': 'the console to use for the d8 shell'
}
}
def GetOptions():
result = Options()
result.Add('mode', 'compilation mode (debug, release)', 'release')
result.Add('sample', 'build sample (shell, process)', '')
result.Add('env', 'override environment settings (NAME1:value1,NAME2:value2)', '')
for (name, option) in SIMPLE_OPTIONS.iteritems():
help = '%s (%s)' % (name, ", ".join(option['values']))
result.Add(name, help, option.get('default'))
return result
def SplitList(str):
return [ s for s in str.split(",") if len(s) > 0 ]
def IsLegal(env, option, values):
str = env[option]
for s in SplitList(str):
if not s in values:
Abort("Illegal value for option %s '%s'." % (option, s))
return False
return True
def VerifyOptions(env):
if not IsLegal(env, 'mode', ['debug', 'release']):
return False
if not IsLegal(env, 'sample', ["shell", "process"]):
return False
if env['os'] == 'win32' and env['library'] == 'shared' and env['prof'] == 'on':
Abort("Profiling on windows only supported for static library.")
for (name, option) in SIMPLE_OPTIONS.iteritems():
if (not option.get('default')) and (name not in ARGUMENTS):
message = ("A value for option %s must be specified (%s)." %
(name, ", ".join(option['values'])))
Abort(message)
if not env[name] in option['values']:
message = ("Unknown %s value '%s'. Possible values are (%s)." %
(name, env[name], ", ".join(option['values'])))
Abort(message)
class BuildContext(object):
def __init__(self, options, env_overrides, samples):
self.library_targets = []
self.cctest_targets = []
self.sample_targets = []
self.d8_targets = []
self.options = options
self.env_overrides = env_overrides
self.samples = samples
self.use_snapshot = (options['snapshot'] == 'on')
self.flags = None
def AddRelevantFlags(self, initial, flags):
result = initial.copy()
self.AppendFlags(result, flags.get('all'))
toolchain = self.options['toolchain']
self.AppendFlags(result, flags[toolchain].get('all'))
for option in sorted(self.options.keys()):
value = self.options[option]
self.AppendFlags(result, flags[toolchain].get(option + ':' + value))
return result
def GetRelevantSources(self, source):
result = []
result += source.get('all', [])
for (name, value) in self.options.iteritems():
result += source.get(name + ':' + value, [])
return sorted(result)
def AppendFlags(self, options, added):
if not added:
return
for (key, value) in added.iteritems():
if not key in options:
options[key] = value
else:
prefix = options[key]
if isinstance(prefix, StringTypes): prefix = prefix.split()
options[key] = prefix + value
def ConfigureObject(self, env, input, **kw):
if self.options['library'] == 'static':
return env.StaticObject(input, **kw)
else:
return env.SharedObject(input, **kw)
def ApplyEnvOverrides(self, env):
if not self.env_overrides:
return
if type(env['ENV']) == DictType:
env['ENV'].update(**self.env_overrides)
else:
env['ENV'] = self.env_overrides
def PostprocessOptions(options):
# Adjust architecture if the simulator option has been set
if (options['simulator'] != 'none') and (options['arch'] != options['simulator']):
if 'arch' in ARGUMENTS:
# Print a warning if arch has explicitly been set
print "Warning: forcing architecture to match simulator (%s)" % options['simulator']
options['arch'] = options['simulator']
def ParseEnvOverrides(arg):
# The environment overrides are in the format NAME1:value1,NAME2:value2
overrides = {}
for override in arg.split(','):
pos = override.find(':')
if pos == -1:
continue
overrides[override[:pos].strip()] = override[pos+1:].strip()
return overrides
def BuildSpecific(env, mode, env_overrides):
options = {'mode': mode}
for option in SIMPLE_OPTIONS:
options[option] = env[option]
PostprocessOptions(options)
context = BuildContext(options, env_overrides, samples=SplitList(env['sample']))
library_flags = context.AddRelevantFlags(os.environ, LIBRARY_FLAGS)
v8_flags = context.AddRelevantFlags(library_flags, V8_EXTRA_FLAGS)
jscre_flags = context.AddRelevantFlags(library_flags, JSCRE_EXTRA_FLAGS)
dtoa_flags = context.AddRelevantFlags(library_flags, DTOA_EXTRA_FLAGS)
cctest_flags = context.AddRelevantFlags(v8_flags, CCTEST_EXTRA_FLAGS)
sample_flags = context.AddRelevantFlags(os.environ, SAMPLE_FLAGS)
d8_flags = context.AddRelevantFlags(library_flags, D8_FLAGS)
context.flags = {
'v8': v8_flags,
'jscre': jscre_flags,
'dtoa': dtoa_flags,
'cctest': cctest_flags,
'sample': sample_flags,
'd8': d8_flags
}
target_id = mode
suffix = SUFFIXES[target_id]
library_name = 'v8' + suffix
env['LIBRARY'] = library_name
# Build the object files by invoking SCons recursively.
(object_files, shell_files) = env.SConscript(
join('src', 'SConscript'),
build_dir=join('obj', target_id),
exports='context',
duplicate=False
)
# Link the object files into a library.
env.Replace(**context.flags['v8'])
context.ApplyEnvOverrides(env)
if context.options['library'] == 'static':
library = env.StaticLibrary(library_name, object_files)
else:
# There seems to be a glitch in the way scons decides where to put
# PDB files when compiling using MSVC so we specify it manually.
# This should not affect any other platforms.
pdb_name = library_name + '.dll.pdb'
library = env.SharedLibrary(library_name, object_files, PDB=pdb_name)
context.library_targets.append(library)
d8_env = Environment()
d8_env.Replace(**context.flags['d8'])
shell = d8_env.Program('d8' + suffix, object_files + shell_files)
context.d8_targets.append(shell)
for sample in context.samples:
sample_env = Environment(LIBRARY=library_name)
sample_env.Replace(**context.flags['sample'])
context.ApplyEnvOverrides(sample_env)
sample_object = sample_env.SConscript(
join('samples', 'SConscript'),
build_dir=join('obj', 'sample', sample, target_id),
exports='sample context',
duplicate=False
)
sample_name = sample + suffix
sample_program = sample_env.Program(sample_name, sample_object)
sample_env.Depends(sample_program, library)
context.sample_targets.append(sample_program)
cctest_program = env.SConscript(
join('test', 'cctest', 'SConscript'),
build_dir=join('obj', 'test', target_id),
exports='context object_files',
duplicate=False
)
context.cctest_targets.append(cctest_program)
return context
def Build():
opts = GetOptions()
env = Environment(options=opts)
Help(opts.GenerateHelpText(env))
VerifyOptions(env)
env_overrides = ParseEnvOverrides(env['env'])
SourceSignatures(env['sourcesignatures'])
libraries = []
cctests = []
samples = []
d8s = []
modes = SplitList(env['mode'])
for mode in modes:
context = BuildSpecific(env.Copy(), mode, env_overrides)
libraries += context.library_targets
cctests += context.cctest_targets
samples += context.sample_targets
d8s += context.d8_targets
env.Alias('library', libraries)
env.Alias('cctests', cctests)
env.Alias('sample', samples)
env.Alias('d8', d8s)
if env['sample']:
env.Default('sample')
else:
env.Default('library')
# We disable deprecation warnings because we need to be able to use
# env.Copy without getting warnings for compatibility with older
# version of scons. Also, there's a bug in some revisions that
# doesn't allow this flag to be set, so we swallow any exceptions.
# Lovely.
try:
SetOption('warn', 'no-deprecated')
except:
pass
Build()

View File

@ -1,29 +0,0 @@
V8 Benchmark Suite
==================
This is the V8 benchmark suite: A collection of pure JavaScript
benchmarks that we have used to tune V8. The licenses for the
individual benchmarks are included in the JavaScript files.
In addition to the benchmarks, the suite consists of the benchmark
framework (base.js), which must be loaded before any of the individual
benchmark files, and two benchmark runners: An HTML version (run.html)
and a standalone JavaScript version (run.js).
Changes From Version 1 To Version 2
===================================
For version 2 the crypto benchmark was fixed. Previously, the
decryption stage was given plaintext as input, which resulted in an
error. Now, the decryption stage is given the output of the
encryption stage as input. The result is checked against the original
plaintext. For this to give the correct results the crypto objects
are reset for each iteration of the benchmark. In addition, the size
of the plain text has been increased a little and the use of
Math.random() and new Date() to build an RNG pool has been removed.
Other benchmarks were fixed to do elementary verification of the
results of their calculations. This is to avoid accidentally
obtaining scores that are the result of an incorrect JavaScript engine
optimization.

View File

@ -1,221 +0,0 @@
// Copyright 2008 the V8 project 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.
// Simple framework for running the benchmark suites and
// computing a score based on the timing measurements.
// A benchmark has a name (string) and a function that will be run to
// do the performance measurement.
function Benchmark(name, run) {
this.name = name;
this.run = run;
}
// Benchmark results hold the benchmark and the measured time used to
// run the benchmark. The benchmark score is computed later once a
// full benchmark suite has run to completion.
function BenchmarkResult(benchmark, time) {
this.benchmark = benchmark;
this.time = time;
}
// Automatically convert results to numbers. Used by the geometric
// mean computation.
BenchmarkResult.prototype.valueOf = function() {
return this.time;
}
// Suites of benchmarks consist of a name and the set of benchmarks in
// addition to the reference timing that the final score will be based
// on. This way, all scores are relative to a reference run and higher
// scores implies better performance.
function BenchmarkSuite(name, reference, benchmarks) {
this.name = name;
this.reference = reference;
this.benchmarks = benchmarks;
BenchmarkSuite.suites.push(this);
}
// Keep track of all declared benchmark suites.
BenchmarkSuite.suites = [];
// Scores are not comparable across versions. Bump the version if
// you're making changes that will affect that scores, e.g. if you add
// a new benchmark or change an existing one.
BenchmarkSuite.version = '2';
// To make the benchmark results predictable, we replace Math.random
// with a 100% deterministic alternative.
Math.random = (function() {
var seed = 49734321;
return function() {
// Robert Jenkins' 32 bit integer hash function.
seed = ((seed + 0x7ed55d16) + (seed << 12)) & 0xffffffff;
seed = ((seed ^ 0xc761c23c) ^ (seed >>> 19)) & 0xffffffff;
seed = ((seed + 0x165667b1) + (seed << 5)) & 0xffffffff;
seed = ((seed + 0xd3a2646c) ^ (seed << 9)) & 0xffffffff;
seed = ((seed + 0xd3a2646c) ^ (seed << 9)) & 0xffffffff;
seed = ((seed + 0xfd7046c5) + (seed << 3)) & 0xffffffff;
seed = ((seed ^ 0xb55a4f09) ^ (seed >>> 16)) & 0xffffffff;
return (seed & 0xfffffff) / 0x10000000;
};
})();
// Runs all registered benchmark suites and optionally yields between
// each individual benchmark to avoid running for too long in the
// context of browsers. Once done, the final score is reported to the
// runner.
BenchmarkSuite.RunSuites = function(runner) {
var continuation = null;
var suites = BenchmarkSuite.suites;
var length = suites.length;
BenchmarkSuite.scores = [];
var index = 0;
function RunStep() {
while (continuation || index < length) {
if (continuation) {
continuation = continuation();
} else {
var suite = suites[index++];
if (runner.NotifyStart) runner.NotifyStart(suite.name);
continuation = suite.RunStep(runner);
}
if (continuation && typeof window != 'undefined' && window.setTimeout) {
window.setTimeout(RunStep, 100);
return;
}
}
if (runner.NotifyScore) {
var score = BenchmarkSuite.GeometricMean(BenchmarkSuite.scores);
runner.NotifyScore(Math.round(100 * score));
}
}
RunStep();
}
// Counts the total number of registered benchmarks. Useful for
// showing progress as a percentage.
BenchmarkSuite.CountBenchmarks = function() {
var result = 0;
var suites = BenchmarkSuite.suites;
for (var i = 0; i < suites.length; i++) {
result += suites[i].benchmarks.length;
}
return result;
}
// Computes the geometric mean of a set of numbers.
BenchmarkSuite.GeometricMean = function(numbers) {
var log = 0;
for (var i = 0; i < numbers.length; i++) {
log += Math.log(numbers[i]);
}
return Math.pow(Math.E, log / numbers.length);
}
// Notifies the runner that we're done running a single benchmark in
// the benchmark suite. This can be useful to report progress.
BenchmarkSuite.prototype.NotifyStep = function(result) {
this.results.push(result);
if (this.runner.NotifyStep) this.runner.NotifyStep(result.benchmark.name);
}
// Notifies the runner that we're done with running a suite and that
// we have a result which can be reported to the user if needed.
BenchmarkSuite.prototype.NotifyResult = function() {
var mean = BenchmarkSuite.GeometricMean(this.results);
var score = this.reference / mean;
BenchmarkSuite.scores.push(score);
if (this.runner.NotifyResult) {
this.runner.NotifyResult(this.name, Math.round(100 * score));
}
}
// Notifies the runner that running a benchmark resulted in an error.
BenchmarkSuite.prototype.NotifyError = function(error) {
if (this.runner.NotifyError) {
this.runner.NotifyError(this.name, error);
}
if (this.runner.NotifyStep) {
this.runner.NotifyStep(this.name);
}
}
// Runs a single benchmark for at least a second and computes the
// average time it takes to run a single iteration.
BenchmarkSuite.prototype.RunSingle = function(benchmark) {
var elapsed = 0;
var start = new Date();
for (var n = 0; elapsed < 1000; n++) {
benchmark.run();
elapsed = new Date() - start;
}
var usec = (elapsed * 1000) / n;
this.NotifyStep(new BenchmarkResult(benchmark, usec));
}
// This function starts running a suite, but stops between each
// individual benchmark in the suite and returns a continuation
// function which can be invoked to run the next benchmark. Once the
// last benchmark has been executed, null is returned.
BenchmarkSuite.prototype.RunStep = function(runner) {
this.results = [];
this.runner = runner;
var length = this.benchmarks.length;
var index = 0;
var suite = this;
function RunNext() {
if (index < length) {
try {
suite.RunSingle(suite.benchmarks[index++]);
} catch (e) {
suite.NotifyError(e);
return null;
}
return RunNext;
}
suite.NotifyResult();
return null;
}
return RunNext();
}

File diff suppressed because it is too large Load Diff

View File

@ -1,880 +0,0 @@
// Copyright 2008 the V8 project authors. All rights reserved.
// Copyright 1996 John Maloney and Mario Wolczko.
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// This implementation of the DeltaBlue benchmark is derived
// from the Smalltalk implementation by John Maloney and Mario
// Wolczko. Some parts have been translated directly, whereas
// others have been modified more aggresively to make it feel
// more like a JavaScript program.
var DeltaBlue = new BenchmarkSuite('DeltaBlue', 71104, [
new Benchmark('DeltaBlue', deltaBlue)
]);
/**
* A JavaScript implementation of the DeltaBlue constrain-solving
* algorithm, as described in:
*
* "The DeltaBlue Algorithm: An Incremental Constraint Hierarchy Solver"
* Bjorn N. Freeman-Benson and John Maloney
* January 1990 Communications of the ACM,
* also available as University of Washington TR 89-08-06.
*
* Beware: this benchmark is written in a grotesque style where
* the constraint model is built by side-effects from constructors.
* I've kept it this way to avoid deviating too much from the original
* implementation.
*/
/* --- O b j e c t M o d e l --- */
Object.prototype.inherits = function (shuper) {
function Inheriter() { }
Inheriter.prototype = shuper.prototype;
this.prototype = new Inheriter();
this.superConstructor = shuper;
}
function OrderedCollection() {
this.elms = new Array();
}
OrderedCollection.prototype.add = function (elm) {
this.elms.push(elm);
}
OrderedCollection.prototype.at = function (index) {
return this.elms[index];
}
OrderedCollection.prototype.size = function () {
return this.elms.length;
}
OrderedCollection.prototype.removeFirst = function () {
return this.elms.pop();
}
OrderedCollection.prototype.remove = function (elm) {
var index = 0, skipped = 0;
for (var i = 0; i < this.elms.length; i++) {
var value = this.elms[i];
if (value != elm) {
this.elms[index] = value;
index++;
} else {
skipped++;
}
}
for (var i = 0; i < skipped; i++)
this.elms.pop();
}
/* --- *
* S t r e n g t h
* --- */
/**
* Strengths are used to measure the relative importance of constraints.
* New strengths may be inserted in the strength hierarchy without
* disrupting current constraints. Strengths cannot be created outside
* this class, so pointer comparison can be used for value comparison.
*/
function Strength(strengthValue, name) {
this.strengthValue = strengthValue;
this.name = name;
}
Strength.stronger = function (s1, s2) {
return s1.strengthValue < s2.strengthValue;
}
Strength.weaker = function (s1, s2) {
return s1.strengthValue > s2.strengthValue;
}
Strength.weakestOf = function (s1, s2) {
return this.weaker(s1, s2) ? s1 : s2;
}
Strength.strongest = function (s1, s2) {
return this.stronger(s1, s2) ? s1 : s2;
}
Strength.prototype.nextWeaker = function () {
switch (this.strengthValue) {
case 0: return Strength.WEAKEST;
case 1: return Strength.WEAK_DEFAULT;
case 2: return Strength.NORMAL;
case 3: return Strength.STRONG_DEFAULT;
case 4: return Strength.PREFERRED;
case 5: return Strength.REQUIRED;
}
}
// Strength constants.
Strength.REQUIRED = new Strength(0, "required");
Strength.STONG_PREFERRED = new Strength(1, "strongPreferred");
Strength.PREFERRED = new Strength(2, "preferred");
Strength.STRONG_DEFAULT = new Strength(3, "strongDefault");
Strength.NORMAL = new Strength(4, "normal");
Strength.WEAK_DEFAULT = new Strength(5, "weakDefault");
Strength.WEAKEST = new Strength(6, "weakest");
/* --- *
* C o n s t r a i n t
* --- */
/**
* An abstract class representing a system-maintainable relationship
* (or "constraint") between a set of variables. A constraint supplies
* a strength instance variable; concrete subclasses provide a means
* of storing the constrained variables and other information required
* to represent a constraint.
*/
function Constraint(strength) {
this.strength = strength;
}
/**
* Activate this constraint and attempt to satisfy it.
*/
Constraint.prototype.addConstraint = function () {
this.addToGraph();
planner.incrementalAdd(this);
}
/**
* Attempt to find a way to enforce this constraint. If successful,
* record the solution, perhaps modifying the current dataflow
* graph. Answer the constraint that this constraint overrides, if
* there is one, or nil, if there isn't.
* Assume: I am not already satisfied.
*/
Constraint.prototype.satisfy = function (mark) {
this.chooseMethod(mark);
if (!this.isSatisfied()) {
if (this.strength == Strength.REQUIRED)
alert("Could not satisfy a required constraint!");
return null;
}
this.markInputs(mark);
var out = this.output();
var overridden = out.determinedBy;
if (overridden != null) overridden.markUnsatisfied();
out.determinedBy = this;
if (!planner.addPropagate(this, mark))
alert("Cycle encountered");
out.mark = mark;
return overridden;
}
Constraint.prototype.destroyConstraint = function () {
if (this.isSatisfied()) planner.incrementalRemove(this);
else this.removeFromGraph();
}
/**
* Normal constraints are not input constraints. An input constraint
* is one that depends on external state, such as the mouse, the
* keybord, a clock, or some arbitraty piece of imperative code.
*/
Constraint.prototype.isInput = function () {
return false;
}
/* --- *
* U n a r y C o n s t r a i n t
* --- */
/**
* Abstract superclass for constraints having a single possible output
* variable.
*/
function UnaryConstraint(v, strength) {
UnaryConstraint.superConstructor.call(this, strength);
this.myOutput = v;
this.satisfied = false;
this.addConstraint();
}
UnaryConstraint.inherits(Constraint);
/**
* Adds this constraint to the constraint graph
*/
UnaryConstraint.prototype.addToGraph = function () {
this.myOutput.addConstraint(this);
this.satisfied = false;
}
/**
* Decides if this constraint can be satisfied and records that
* decision.
*/
UnaryConstraint.prototype.chooseMethod = function (mark) {
this.satisfied = (this.myOutput.mark != mark)
&& Strength.stronger(this.strength, this.myOutput.walkStrength);
}
/**
* Returns true if this constraint is satisfied in the current solution.
*/
UnaryConstraint.prototype.isSatisfied = function () {
return this.satisfied;
}
UnaryConstraint.prototype.markInputs = function (mark) {
// has no inputs
}
/**
* Returns the current output variable.
*/
UnaryConstraint.prototype.output = function () {
return this.myOutput;
}
/**
* Calculate the walkabout strength, the stay flag, and, if it is
* 'stay', the value for the current output of this constraint. Assume
* this constraint is satisfied.
*/
UnaryConstraint.prototype.recalculate = function () {
this.myOutput.walkStrength = this.strength;
this.myOutput.stay = !this.isInput();
if (this.myOutput.stay) this.execute(); // Stay optimization
}
/**
* Records that this constraint is unsatisfied
*/
UnaryConstraint.prototype.markUnsatisfied = function () {
this.satisfied = false;
}
UnaryConstraint.prototype.inputsKnown = function () {
return true;
}
UnaryConstraint.prototype.removeFromGraph = function () {
if (this.myOutput != null) this.myOutput.removeConstraint(this);
this.satisfied = false;
}
/* --- *
* S t a y C o n s t r a i n t
* --- */
/**
* Variables that should, with some level of preference, stay the same.
* Planners may exploit the fact that instances, if satisfied, will not
* change their output during plan execution. This is called "stay
* optimization".
*/
function StayConstraint(v, str) {
StayConstraint.superConstructor.call(this, v, str);
}
StayConstraint.inherits(UnaryConstraint);
StayConstraint.prototype.execute = function () {
// Stay constraints do nothing
}
/* --- *
* E d i t C o n s t r a i n t
* --- */
/**
* A unary input constraint used to mark a variable that the client
* wishes to change.
*/
function EditConstraint(v, str) {
EditConstraint.superConstructor.call(this, v, str);
}
EditConstraint.inherits(UnaryConstraint);
/**
* Edits indicate that a variable is to be changed by imperative code.
*/
EditConstraint.prototype.isInput = function () {
return true;
}
EditConstraint.prototype.execute = function () {
// Edit constraints do nothing
}
/* --- *
* B i n a r y C o n s t r a i n t
* --- */
var Direction = new Object();
Direction.NONE = 0;
Direction.FORWARD = 1;
Direction.BACKWARD = -1;
/**
* Abstract superclass for constraints having two possible output
* variables.
*/
function BinaryConstraint(var1, var2, strength) {
BinaryConstraint.superConstructor.call(this, strength);
this.v1 = var1;
this.v2 = var2;
this.direction = Direction.NONE;
this.addConstraint();
}
BinaryConstraint.inherits(Constraint);
/**
* Decides if this constratint can be satisfied and which way it
* should flow based on the relative strength of the variables related,
* and record that decision.
*/
BinaryConstraint.prototype.chooseMethod = function (mark) {
if (this.v1.mark == mark) {
this.direction = (this.v1.mark != mark && Strength.stronger(this.strength, this.v2.walkStrength))
? Direction.FORWARD
: Direction.NONE;
}
if (this.v2.mark == mark) {
this.direction = (this.v1.mark != mark && Strength.stronger(this.strength, this.v1.walkStrength))
? Direction.BACKWARD
: Direction.NONE;
}
if (Strength.weaker(this.v1.walkStrength, this.v2.walkStrength)) {
this.direction = Strength.stronger(this.strength, this.v1.walkStrength)
? Direction.BACKWARD
: Direction.NONE;
} else {
this.direction = Strength.stronger(this.strength, this.v2.walkStrength)
? Direction.FORWARD
: Direction.BACKWARD
}
}
/**
* Add this constraint to the constraint graph
*/
BinaryConstraint.prototype.addToGraph = function () {
this.v1.addConstraint(this);
this.v2.addConstraint(this);
this.direction = Direction.NONE;
}
/**
* Answer true if this constraint is satisfied in the current solution.
*/
BinaryConstraint.prototype.isSatisfied = function () {
return this.direction != Direction.NONE;
}
/**
* Mark the input variable with the given mark.
*/
BinaryConstraint.prototype.markInputs = function (mark) {
this.input().mark = mark;
}
/**
* Returns the current input variable
*/
BinaryConstraint.prototype.input = function () {
return (this.direction == Direction.FORWARD) ? this.v1 : this.v2;
}
/**
* Returns the current output variable
*/
BinaryConstraint.prototype.output = function () {
return (this.direction == Direction.FORWARD) ? this.v2 : this.v1;
}
/**
* Calculate the walkabout strength, the stay flag, and, if it is
* 'stay', the value for the current output of this
* constraint. Assume this constraint is satisfied.
*/
BinaryConstraint.prototype.recalculate = function () {
var ihn = this.input(), out = this.output();
out.walkStrength = Strength.weakestOf(this.strength, ihn.walkStrength);
out.stay = ihn.stay;
if (out.stay) this.execute();
}
/**
* Record the fact that this constraint is unsatisfied.
*/
BinaryConstraint.prototype.markUnsatisfied = function () {
this.direction = Direction.NONE;
}
BinaryConstraint.prototype.inputsKnown = function (mark) {
var i = this.input();
return i.mark == mark || i.stay || i.determinedBy == null;
}
BinaryConstraint.prototype.removeFromGraph = function () {
if (this.v1 != null) this.v1.removeConstraint(this);
if (this.v2 != null) this.v2.removeConstraint(this);
this.direction = Direction.NONE;
}
/* --- *
* S c a l e C o n s t r a i n t
* --- */
/**
* Relates two variables by the linear scaling relationship: "v2 =
* (v1 * scale) + offset". Either v1 or v2 may be changed to maintain
* this relationship but the scale factor and offset are considered
* read-only.
*/
function ScaleConstraint(src, scale, offset, dest, strength) {
this.direction = Direction.NONE;
this.scale = scale;
this.offset = offset;
ScaleConstraint.superConstructor.call(this, src, dest, strength);
}
ScaleConstraint.inherits(BinaryConstraint);
/**
* Adds this constraint to the constraint graph.
*/
ScaleConstraint.prototype.addToGraph = function () {
ScaleConstraint.superConstructor.prototype.addToGraph.call(this);
this.scale.addConstraint(this);
this.offset.addConstraint(this);
}
ScaleConstraint.prototype.removeFromGraph = function () {
ScaleConstraint.superConstructor.prototype.removeFromGraph.call(this);
if (this.scale != null) this.scale.removeConstraint(this);
if (this.offset != null) this.offset.removeConstraint(this);
}
ScaleConstraint.prototype.markInputs = function (mark) {
ScaleConstraint.superConstructor.prototype.markInputs.call(this, mark);
this.scale.mark = this.offset.mark = mark;
}
/**
* Enforce this constraint. Assume that it is satisfied.
*/
ScaleConstraint.prototype.execute = function () {
if (this.direction == Direction.FORWARD) {
this.v2.value = this.v1.value * this.scale.value + this.offset.value;
} else {
this.v1.value = (this.v2.value - this.offset.value) / this.scale.value;
}
}
/**
* Calculate the walkabout strength, the stay flag, and, if it is
* 'stay', the value for the current output of this constraint. Assume
* this constraint is satisfied.
*/
ScaleConstraint.prototype.recalculate = function () {
var ihn = this.input(), out = this.output();
out.walkStrength = Strength.weakestOf(this.strength, ihn.walkStrength);
out.stay = ihn.stay && this.scale.stay && this.offset.stay;
if (out.stay) this.execute();
}
/* --- *
* E q u a l i t y C o n s t r a i n t
* --- */
/**
* Constrains two variables to have the same value.
*/
function EqualityConstraint(var1, var2, strength) {
EqualityConstraint.superConstructor.call(this, var1, var2, strength);
}
EqualityConstraint.inherits(BinaryConstraint);
/**
* Enforce this constraint. Assume that it is satisfied.
*/
EqualityConstraint.prototype.execute = function () {
this.output().value = this.input().value;
}
/* --- *
* V a r i a b l e
* --- */
/**
* A constrained variable. In addition to its value, it maintain the
* structure of the constraint graph, the current dataflow graph, and
* various parameters of interest to the DeltaBlue incremental
* constraint solver.
**/
function Variable(name, initialValue) {
this.value = initialValue || 0;
this.constraints = new OrderedCollection();
this.determinedBy = null;
this.mark = 0;
this.walkStrength = Strength.WEAKEST;
this.stay = true;
this.name = name;
}
/**
* Add the given constraint to the set of all constraints that refer
* this variable.
*/
Variable.prototype.addConstraint = function (c) {
this.constraints.add(c);
}
/**
* Removes all traces of c from this variable.
*/
Variable.prototype.removeConstraint = function (c) {
this.constraints.remove(c);
if (this.determinedBy == c) this.determinedBy = null;
}
/* --- *
* P l a n n e r
* --- */
/**
* The DeltaBlue planner
*/
function Planner() {
this.currentMark = 0;
}
/**
* Attempt to satisfy the given constraint and, if successful,
* incrementally update the dataflow graph. Details: If satifying
* the constraint is successful, it may override a weaker constraint
* on its output. The algorithm attempts to resatisfy that
* constraint using some other method. This process is repeated
* until either a) it reaches a variable that was not previously
* determined by any constraint or b) it reaches a constraint that
* is too weak to be satisfied using any of its methods. The
* variables of constraints that have been processed are marked with
* a unique mark value so that we know where we've been. This allows
* the algorithm to avoid getting into an infinite loop even if the
* constraint graph has an inadvertent cycle.
*/
Planner.prototype.incrementalAdd = function (c) {
var mark = this.newMark();
var overridden = c.satisfy(mark);
while (overridden != null)
overridden = overridden.satisfy(mark);
}
/**
* Entry point for retracting a constraint. Remove the given
* constraint and incrementally update the dataflow graph.
* Details: Retracting the given constraint may allow some currently
* unsatisfiable downstream constraint to be satisfied. We therefore collect
* a list of unsatisfied downstream constraints and attempt to
* satisfy each one in turn. This list is traversed by constraint
* strength, strongest first, as a heuristic for avoiding
* unnecessarily adding and then overriding weak constraints.
* Assume: c is satisfied.
*/
Planner.prototype.incrementalRemove = function (c) {
var out = c.output();
c.markUnsatisfied();
c.removeFromGraph();
var unsatisfied = this.removePropagateFrom(out);
var strength = Strength.REQUIRED;
do {
for (var i = 0; i < unsatisfied.size(); i++) {
var u = unsatisfied.at(i);
if (u.strength == strength)
this.incrementalAdd(u);
}
strength = strength.nextWeaker();
} while (strength != Strength.WEAKEST);
}
/**
* Select a previously unused mark value.
*/
Planner.prototype.newMark = function () {
return ++this.currentMark;
}
/**
* Extract a plan for resatisfaction starting from the given source
* constraints, usually a set of input constraints. This method
* assumes that stay optimization is desired; the plan will contain
* only constraints whose output variables are not stay. Constraints
* that do no computation, such as stay and edit constraints, are
* not included in the plan.
* Details: The outputs of a constraint are marked when it is added
* to the plan under construction. A constraint may be appended to
* the plan when all its input variables are known. A variable is
* known if either a) the variable is marked (indicating that has
* been computed by a constraint appearing earlier in the plan), b)
* the variable is 'stay' (i.e. it is a constant at plan execution
* time), or c) the variable is not determined by any
* constraint. The last provision is for past states of history
* variables, which are not stay but which are also not computed by
* any constraint.
* Assume: sources are all satisfied.
*/
Planner.prototype.makePlan = function (sources) {
var mark = this.newMark();
var plan = new Plan();
var todo = sources;
while (todo.size() > 0) {
var c = todo.removeFirst();
if (c.output().mark != mark && c.inputsKnown(mark)) {
plan.addConstraint(c);
c.output().mark = mark;
this.addConstraintsConsumingTo(c.output(), todo);
}
}
return plan;
}
/**
* Extract a plan for resatisfying starting from the output of the
* given constraints, usually a set of input constraints.
*/
Planner.prototype.extractPlanFromConstraints = function (constraints) {
var sources = new OrderedCollection();
for (var i = 0; i < constraints.size(); i++) {
var c = constraints.at(i);
if (c.isInput() && c.isSatisfied())
// not in plan already and eligible for inclusion
sources.add(c);
}
return this.makePlan(sources);
}
/**
* Recompute the walkabout strengths and stay flags of all variables
* downstream of the given constraint and recompute the actual
* values of all variables whose stay flag is true. If a cycle is
* detected, remove the given constraint and answer
* false. Otherwise, answer true.
* Details: Cycles are detected when a marked variable is
* encountered downstream of the given constraint. The sender is
* assumed to have marked the inputs of the given constraint with
* the given mark. Thus, encountering a marked node downstream of
* the output constraint means that there is a path from the
* constraint's output to one of its inputs.
*/
Planner.prototype.addPropagate = function (c, mark) {
var todo = new OrderedCollection();
todo.add(c);
while (todo.size() > 0) {
var d = todo.removeFirst();
if (d.output().mark == mark) {
this.incrementalRemove(c);
return false;
}
d.recalculate();
this.addConstraintsConsumingTo(d.output(), todo);
}
return true;
}
/**
* Update the walkabout strengths and stay flags of all variables
* downstream of the given constraint. Answer a collection of
* unsatisfied constraints sorted in order of decreasing strength.
*/
Planner.prototype.removePropagateFrom = function (out) {
out.determinedBy = null;
out.walkStrength = Strength.WEAKEST;
out.stay = true;
var unsatisfied = new OrderedCollection();
var todo = new OrderedCollection();
todo.add(out);
while (todo.size() > 0) {
var v = todo.removeFirst();
for (var i = 0; i < v.constraints.size(); i++) {
var c = v.constraints.at(i);
if (!c.isSatisfied())
unsatisfied.add(c);
}
var determining = v.determinedBy;
for (var i = 0; i < v.constraints.size(); i++) {
var next = v.constraints.at(i);
if (next != determining && next.isSatisfied()) {
next.recalculate();
todo.add(next.output());
}
}
}
return unsatisfied;
}
Planner.prototype.addConstraintsConsumingTo = function (v, coll) {
var determining = v.determinedBy;
var cc = v.constraints;
for (var i = 0; i < cc.size(); i++) {
var c = cc.at(i);
if (c != determining && c.isSatisfied())
coll.add(c);
}
}
/* --- *
* P l a n
* --- */
/**
* A Plan is an ordered list of constraints to be executed in sequence
* to resatisfy all currently satisfiable constraints in the face of
* one or more changing inputs.
*/
function Plan() {
this.v = new OrderedCollection();
}
Plan.prototype.addConstraint = function (c) {
this.v.add(c);
}
Plan.prototype.size = function () {
return this.v.size();
}
Plan.prototype.constraintAt = function (index) {
return this.v.at(index);
}
Plan.prototype.execute = function () {
for (var i = 0; i < this.size(); i++) {
var c = this.constraintAt(i);
c.execute();
}
}
/* --- *
* M a i n
* --- */
/**
* This is the standard DeltaBlue benchmark. A long chain of equality
* constraints is constructed with a stay constraint on one end. An
* edit constraint is then added to the opposite end and the time is
* measured for adding and removing this constraint, and extracting
* and executing a constraint satisfaction plan. There are two cases.
* In case 1, the added constraint is stronger than the stay
* constraint and values must propagate down the entire length of the
* chain. In case 2, the added constraint is weaker than the stay
* constraint so it cannot be accomodated. The cost in this case is,
* of course, very low. Typical situations lie somewhere between these
* two extremes.
*/
function chainTest(n) {
planner = new Planner();
var prev = null, first = null, last = null;
// Build chain of n equality constraints
for (var i = 0; i <= n; i++) {
var name = "v" + i;
var v = new Variable(name);
if (prev != null)
new EqualityConstraint(prev, v, Strength.REQUIRED);
if (i == 0) first = v;
if (i == n) last = v;
prev = v;
}
new StayConstraint(last, Strength.STRONG_DEFAULT);
var edit = new EditConstraint(first, Strength.PREFERRED);
var edits = new OrderedCollection();
edits.add(edit);
var plan = planner.extractPlanFromConstraints(edits);
for (var i = 0; i < 100; i++) {
first.value = i;
plan.execute();
if (last.value != i)
alert("Chain test failed.");
}
}
/**
* This test constructs a two sets of variables related to each
* other by a simple linear transformation (scale and offset). The
* time is measured to change a variable on either side of the
* mapping and to change the scale and offset factors.
*/
function projectionTest(n) {
planner = new Planner();
var scale = new Variable("scale", 10);
var offset = new Variable("offset", 1000);
var src = null, dst = null;
var dests = new OrderedCollection();
for (var i = 0; i < n; i++) {
src = new Variable("src" + i, i);
dst = new Variable("dst" + i, i);
dests.add(dst);
new StayConstraint(src, Strength.NORMAL);
new ScaleConstraint(src, scale, offset, dst, Strength.REQUIRED);
}
change(src, 17);
if (dst.value != 1170) alert("Projection 1 failed");
change(dst, 1050);
if (src.value != 5) alert("Projection 2 failed");
change(scale, 5);
for (var i = 0; i < n - 1; i++) {
if (dests.at(i).value != i * 5 + 1000)
alert("Projection 3 failed");
}
change(offset, 2000);
for (var i = 0; i < n - 1; i++) {
if (dests.at(i).value != i * 5 + 2000)
alert("Projection 4 failed");
}
}
function change(v, newValue) {
var edit = new EditConstraint(v, Strength.PREFERRED);
var edits = new OrderedCollection();
edits.add(edit);
var plan = planner.extractPlanFromConstraints(edits);
for (var i = 0; i < 10; i++) {
v.value = newValue;
plan.execute();
}
edit.destroyConstraint();
}
// Global variable holding the current planner.
var planner = null;
function deltaBlue() {
chainTest(100);
projectionTest(100);
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -1,539 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
// This is a JavaScript implementation of the Richards
// benchmark from:
//
// http://www.cl.cam.ac.uk/~mr10/Bench.html
//
// The benchmark was originally implemented in BCPL by
// Martin Richards.
var Richards = new BenchmarkSuite('Richards', 34886, [
new Benchmark("Richards", runRichards)
]);
/**
* The Richards benchmark simulates the task dispatcher of an
* operating system.
**/
function runRichards() {
var scheduler = new Scheduler();
scheduler.addIdleTask(ID_IDLE, 0, null, COUNT);
var queue = new Packet(null, ID_WORKER, KIND_WORK);
queue = new Packet(queue, ID_WORKER, KIND_WORK);
scheduler.addWorkerTask(ID_WORKER, 1000, queue);
queue = new Packet(null, ID_DEVICE_A, KIND_DEVICE);
queue = new Packet(queue, ID_DEVICE_A, KIND_DEVICE);
queue = new Packet(queue, ID_DEVICE_A, KIND_DEVICE);
scheduler.addHandlerTask(ID_HANDLER_A, 2000, queue);
queue = new Packet(null, ID_DEVICE_B, KIND_DEVICE);
queue = new Packet(queue, ID_DEVICE_B, KIND_DEVICE);
queue = new Packet(queue, ID_DEVICE_B, KIND_DEVICE);
scheduler.addHandlerTask(ID_HANDLER_B, 3000, queue);
scheduler.addDeviceTask(ID_DEVICE_A, 4000, null);
scheduler.addDeviceTask(ID_DEVICE_B, 5000, null);
scheduler.schedule();
if (scheduler.queueCount != EXPECTED_QUEUE_COUNT ||
scheduler.holdCount != EXPECTED_HOLD_COUNT) {
var msg =
"Error during execution: queueCount = " + scheduler.queueCount +
", holdCount = " + scheduler.holdCount + ".";
throw new Error(msg);
}
}
var COUNT = 1000;
/**
* These two constants specify how many times a packet is queued and
* how many times a task is put on hold in a correct run of richards.
* They don't have any meaning a such but are characteristic of a
* correct run so if the actual queue or hold count is different from
* the expected there must be a bug in the implementation.
**/
var EXPECTED_QUEUE_COUNT = 2322;
var EXPECTED_HOLD_COUNT = 928;
/**
* A scheduler can be used to schedule a set of tasks based on their relative
* priorities. Scheduling is done by maintaining a list of task control blocks
* which holds tasks and the data queue they are processing.
* @constructor
*/
function Scheduler() {
this.queueCount = 0;
this.holdCount = 0;
this.blocks = new Array(NUMBER_OF_IDS);
this.list = null;
this.currentTcb = null;
this.currentId = null;
}
var ID_IDLE = 0;
var ID_WORKER = 1;
var ID_HANDLER_A = 2;
var ID_HANDLER_B = 3;
var ID_DEVICE_A = 4;
var ID_DEVICE_B = 5;
var NUMBER_OF_IDS = 6;
var KIND_DEVICE = 0;
var KIND_WORK = 1;
/**
* Add an idle task to this scheduler.
* @param {int} id the identity of the task
* @param {int} priority the task's priority
* @param {Packet} queue the queue of work to be processed by the task
* @param {int} count the number of times to schedule the task
*/
Scheduler.prototype.addIdleTask = function (id, priority, queue, count) {
this.addRunningTask(id, priority, queue, new IdleTask(this, 1, count));
};
/**
* Add a work task to this scheduler.
* @param {int} id the identity of the task
* @param {int} priority the task's priority
* @param {Packet} queue the queue of work to be processed by the task
*/
Scheduler.prototype.addWorkerTask = function (id, priority, queue) {
this.addTask(id, priority, queue, new WorkerTask(this, ID_HANDLER_A, 0));
};
/**
* Add a handler task to this scheduler.
* @param {int} id the identity of the task
* @param {int} priority the task's priority
* @param {Packet} queue the queue of work to be processed by the task
*/
Scheduler.prototype.addHandlerTask = function (id, priority, queue) {
this.addTask(id, priority, queue, new HandlerTask(this));
};
/**
* Add a handler task to this scheduler.
* @param {int} id the identity of the task
* @param {int} priority the task's priority
* @param {Packet} queue the queue of work to be processed by the task
*/
Scheduler.prototype.addDeviceTask = function (id, priority, queue) {
this.addTask(id, priority, queue, new DeviceTask(this))
};
/**
* Add the specified task and mark it as running.
* @param {int} id the identity of the task
* @param {int} priority the task's priority
* @param {Packet} queue the queue of work to be processed by the task
* @param {Task} task the task to add
*/
Scheduler.prototype.addRunningTask = function (id, priority, queue, task) {
this.addTask(id, priority, queue, task);
this.currentTcb.setRunning();
};
/**
* Add the specified task to this scheduler.
* @param {int} id the identity of the task
* @param {int} priority the task's priority
* @param {Packet} queue the queue of work to be processed by the task
* @param {Task} task the task to add
*/
Scheduler.prototype.addTask = function (id, priority, queue, task) {
this.currentTcb = new TaskControlBlock(this.list, id, priority, queue, task);
this.list = this.currentTcb;
this.blocks[id] = this.currentTcb;
};
/**
* Execute the tasks managed by this scheduler.
*/
Scheduler.prototype.schedule = function () {
this.currentTcb = this.list;
while (this.currentTcb != null) {
if (this.currentTcb.isHeldOrSuspended()) {
this.currentTcb = this.currentTcb.link;
} else {
this.currentId = this.currentTcb.id;
this.currentTcb = this.currentTcb.run();
}
}
};
/**
* Release a task that is currently blocked and return the next block to run.
* @param {int} id the id of the task to suspend
*/
Scheduler.prototype.release = function (id) {
var tcb = this.blocks[id];
if (tcb == null) return tcb;
tcb.markAsNotHeld();
if (tcb.priority > this.currentTcb.priority) {
return tcb;
} else {
return this.currentTcb;
}
};
/**
* Block the currently executing task and return the next task control block
* to run. The blocked task will not be made runnable until it is explicitly
* released, even if new work is added to it.
*/
Scheduler.prototype.holdCurrent = function () {
this.holdCount++;
this.currentTcb.markAsHeld();
return this.currentTcb.link;
};
/**
* Suspend the currently executing task and return the next task control block
* to run. If new work is added to the suspended task it will be made runnable.
*/
Scheduler.prototype.suspendCurrent = function () {
this.currentTcb.markAsSuspended();
return this.currentTcb;
};
/**
* Add the specified packet to the end of the worklist used by the task
* associated with the packet and make the task runnable if it is currently
* suspended.
* @param {Packet} packet the packet to add
*/
Scheduler.prototype.queue = function (packet) {
var t = this.blocks[packet.id];
if (t == null) return t;
this.queueCount++;
packet.link = null;
packet.id = this.currentId;
return t.checkPriorityAdd(this.currentTcb, packet);
};
/**
* A task control block manages a task and the queue of work packages associated
* with it.
* @param {TaskControlBlock} link the preceding block in the linked block list
* @param {int} id the id of this block
* @param {int} priority the priority of this block
* @param {Packet} queue the queue of packages to be processed by the task
* @param {Task} task the task
* @constructor
*/
function TaskControlBlock(link, id, priority, queue, task) {
this.link = link;
this.id = id;
this.priority = priority;
this.queue = queue;
this.task = task;
if (queue == null) {
this.state = STATE_SUSPENDED;
} else {
this.state = STATE_SUSPENDED_RUNNABLE;
}
}
/**
* The task is running and is currently scheduled.
*/
var STATE_RUNNING = 0;
/**
* The task has packets left to process.
*/
var STATE_RUNNABLE = 1;
/**
* The task is not currently running. The task is not blocked as such and may
* be started by the scheduler.
*/
var STATE_SUSPENDED = 2;
/**
* The task is blocked and cannot be run until it is explicitly released.
*/
var STATE_HELD = 4;
var STATE_SUSPENDED_RUNNABLE = STATE_SUSPENDED | STATE_RUNNABLE;
var STATE_NOT_HELD = ~STATE_HELD;
TaskControlBlock.prototype.setRunning = function () {
this.state = STATE_RUNNING;
};
TaskControlBlock.prototype.markAsNotHeld = function () {
this.state = this.state & STATE_NOT_HELD;
};
TaskControlBlock.prototype.markAsHeld = function () {
this.state = this.state | STATE_HELD;
};
TaskControlBlock.prototype.isHeldOrSuspended = function () {
return (this.state & STATE_HELD) != 0 || (this.state == STATE_SUSPENDED);
};
TaskControlBlock.prototype.markAsSuspended = function () {
this.state = this.state | STATE_SUSPENDED;
};
TaskControlBlock.prototype.markAsRunnable = function () {
this.state = this.state | STATE_RUNNABLE;
};
/**
* Runs this task, if it is ready to be run, and returns the next task to run.
*/
TaskControlBlock.prototype.run = function () {
var packet;
if (this.state == STATE_SUSPENDED_RUNNABLE) {
packet = this.queue;
this.queue = packet.link;
if (this.queue == null) {
this.state = STATE_RUNNING;
} else {
this.state = STATE_RUNNABLE;
}
} else {
packet = null;
}
return this.task.run(packet);
};
/**
* Adds a packet to the worklist of this block's task, marks this as runnable if
* necessary, and returns the next runnable object to run (the one
* with the highest priority).
*/
TaskControlBlock.prototype.checkPriorityAdd = function (task, packet) {
if (this.queue == null) {
this.queue = packet;
this.markAsRunnable();
if (this.priority > task.priority) return this;
} else {
this.queue = packet.addTo(this.queue);
}
return task;
};
TaskControlBlock.prototype.toString = function () {
return "tcb { " + this.task + "@" + this.state + " }";
};
/**
* An idle task doesn't do any work itself but cycles control between the two
* device tasks.
* @param {Scheduler} scheduler the scheduler that manages this task
* @param {int} v1 a seed value that controls how the device tasks are scheduled
* @param {int} count the number of times this task should be scheduled
* @constructor
*/
function IdleTask(scheduler, v1, count) {
this.scheduler = scheduler;
this.v1 = v1;
this.count = count;
}
IdleTask.prototype.run = function (packet) {
this.count--;
if (this.count == 0) return this.scheduler.holdCurrent();
if ((this.v1 & 1) == 0) {
this.v1 = this.v1 >> 1;
return this.scheduler.release(ID_DEVICE_A);
} else {
this.v1 = (this.v1 >> 1) ^ 0xD008;
return this.scheduler.release(ID_DEVICE_B);
}
};
IdleTask.prototype.toString = function () {
return "IdleTask"
};
/**
* A task that suspends itself after each time it has been run to simulate
* waiting for data from an external device.
* @param {Scheduler} scheduler the scheduler that manages this task
* @constructor
*/
function DeviceTask(scheduler) {
this.scheduler = scheduler;
this.v1 = null;
}
DeviceTask.prototype.run = function (packet) {
if (packet == null) {
if (this.v1 == null) return this.scheduler.suspendCurrent();
var v = this.v1;
this.v1 = null;
return this.scheduler.queue(v);
} else {
this.v1 = packet;
return this.scheduler.holdCurrent();
}
};
DeviceTask.prototype.toString = function () {
return "DeviceTask";
};
/**
* A task that manipulates work packets.
* @param {Scheduler} scheduler the scheduler that manages this task
* @param {int} v1 a seed used to specify how work packets are manipulated
* @param {int} v2 another seed used to specify how work packets are manipulated
* @constructor
*/
function WorkerTask(scheduler, v1, v2) {
this.scheduler = scheduler;
this.v1 = v1;
this.v2 = v2;
}
WorkerTask.prototype.run = function (packet) {
if (packet == null) {
return this.scheduler.suspendCurrent();
} else {
if (this.v1 == ID_HANDLER_A) {
this.v1 = ID_HANDLER_B;
} else {
this.v1 = ID_HANDLER_A;
}
packet.id = this.v1;
packet.a1 = 0;
for (var i = 0; i < DATA_SIZE; i++) {
this.v2++;
if (this.v2 > 26) this.v2 = 1;
packet.a2[i] = this.v2;
}
return this.scheduler.queue(packet);
}
};
WorkerTask.prototype.toString = function () {
return "WorkerTask";
};
/**
* A task that manipulates work packets and then suspends itself.
* @param {Scheduler} scheduler the scheduler that manages this task
* @constructor
*/
function HandlerTask(scheduler) {
this.scheduler = scheduler;
this.v1 = null;
this.v2 = null;
}
HandlerTask.prototype.run = function (packet) {
if (packet != null) {
if (packet.kind == KIND_WORK) {
this.v1 = packet.addTo(this.v1);
} else {
this.v2 = packet.addTo(this.v2);
}
}
if (this.v1 != null) {
var count = this.v1.a1;
var v;
if (count < DATA_SIZE) {
if (this.v2 != null) {
v = this.v2;
this.v2 = this.v2.link;
v.a1 = this.v1.a2[count];
this.v1.a1 = count + 1;
return this.scheduler.queue(v);
}
} else {
v = this.v1;
this.v1 = this.v1.link;
return this.scheduler.queue(v);
}
}
return this.scheduler.suspendCurrent();
};
HandlerTask.prototype.toString = function () {
return "HandlerTask";
};
/* --- *
* P a c k e t
* --- */
var DATA_SIZE = 4;
/**
* A simple package of data that is manipulated by the tasks. The exact layout
* of the payload data carried by a packet is not importaint, and neither is the
* nature of the work performed on packets by the tasks.
*
* Besides carrying data, packets form linked lists and are hence used both as
* data and worklists.
* @param {Packet} link the tail of the linked list of packets
* @param {int} id an ID for this packet
* @param {int} kind the type of this packet
* @constructor
*/
function Packet(link, id, kind) {
this.link = link;
this.id = id;
this.kind = kind;
this.a1 = 0;
this.a2 = new Array(DATA_SIZE);
}
/**
* Add this packet to the end of a worklist, and return the worklist.
* @param {Packet} queue the worklist to add this packet to
*/
Packet.prototype.addTo = function (queue) {
this.link = null;
if (queue == null) return this;
var peek, next = queue;
while ((peek = next.link) != null)
next = peek;
next.link = this;
return queue;
};
Packet.prototype.toString = function () {
return "Packet";
};

View File

@ -1,171 +0,0 @@
<html>
<head>
<title>V8 Benchmark Suite</title>
<script type="text/javascript" src="base.js"></script>
<script type="text/javascript" src="richards.js"></script>
<script type="text/javascript" src="deltablue.js"></script>
<script type="text/javascript" src="crypto.js"></script>
<script type="text/javascript" src="raytrace.js"></script>
<script type="text/javascript" src="earley-boyer.js"></script>
<style>
body {
font-family: sans-serif;
}
hr{
border:1px solid;
border-color:#36C;
margin:1em 0
}
h1,h2,h3,h4{margin:0; margin-bottom:0}
h1{font-size: 200%; height: 2em}
h2{font-size: 140%; height: 2em}
h3{font-size: 100%; height: 2em}
li{
margin:.3em 0 1em 0;
}
body{
font-family: Helvetica,Arial,sans-serif;
font-size: small;
color: #000;
background-color: #fff;
}
div.title {
background-color: rgb(229, 236, 249);
border-top: 1px solid rgb(51, 102, 204);
text-align: center;
padding-top: 0.2em;
padding-bottom: 0.2em;
margin-bottom: 20px;
}
td.contents {
text-align: start;
}
div.run {
margin: 20px;
width: 300px;
height: 300px;
float: right;
background-color: rgb(229, 236, 249);
background-image: url(v8-logo.png);
background-position: center center;
background-repeat: no-repeat;
border: 1px solid rgb(51, 102, 204);
}
</style>
<script type="text/javascript">
var completed = 0;
var benchmarks = BenchmarkSuite.CountBenchmarks();
var success = true;
function ShowProgress(name) {
var status = document.getElementById("status");
var percentage = ((++completed) / benchmarks) * 100;
status.innerHTML = "Running: " + Math.round(percentage) + "% completed.";
}
function AddResult(name, result) {
var text = name + ': ' + result;
var results = document.getElementById("results");
results.innerHTML += (text + "<br/>");
}
function AddError(name, error) {
AddResult(name, '<b>error</b>');
success = false;
}
function AddScore(score) {
var status = document.getElementById("status");
if (success) {
status.innerHTML = "Score: " + score;
}
}
function Run() {
BenchmarkSuite.RunSuites({ NotifyStep: ShowProgress,
NotifyError: AddError,
NotifyResult: AddResult,
NotifyScore: AddScore });
}
function Load() {
var version = BenchmarkSuite.version;
document.getElementById("version").innerHTML = version;
window.setTimeout(Run, 200);
}
</script>
</head>
<body onLoad="Load()">
<div>
<div class="title"><h1>V8 Benchmark Suite - version <span id="version">?</span></h1></div>
<table>
<tr>
<td class="contents">
This page contains a suite of pure JavaScript benchmarks that we have
used to tune V8. The final score is computed as the geometric mean of
the individual results to make it independent of the running times of
the individual benchmarks and of a reference system (score
100). Scores are not comparable across benchmark suite versions and
higher scores means better performance: <em>Bigger is better!</em>
<ul>
<li><b>Richards</b><br/>OS kernel simulation benchmark, originally written in BCPL by Martin Richards (<i>539 lines</i>).</li>
<li><b>DeltaBlue</b><br/>One-way constraint solver, originally written in Smalltalk by John Maloney and Mario Wolczko (<i>880 lines</i>).</li>
<li><b>Crypto</b><br/>Encryption and decryption benchmark based on code by Tom Wu (<i>1689 lines</i>).</li>
<li><b>RayTrace</b><br/>Ray tracer benchmark based on code by <a href="http://flog.co.nz/">Adam Burmister</a> (<i>3418 lines</i>).</li>
<li><b>EarleyBoyer</b><br/>Classic Scheme benchmarks, translated to JavaScript by Florian Loitsch's Scheme2Js compiler (<i>4682 lines</i>).</li>
</ul>
<div class="title"><h2>Revisions of the benchmark suite</h2></div>
<p><i>Please note that benchmark results are not comparable unless both
results are run with the same revision of the benchmark suite. We will be
making revisions from time to time in order to fix bugs or expand the scope
of the benchmark suite.</i></p>
<div class="title"><h3>Version 1</h3></div>
<p>Initial release.</p>
<div class="title"><h3>Version 2</h3></div>
<p>For version 2 the crypto benchmark was fixed. Previously, the
decryption stage was given plaintext as input, which resulted in an
error. Now, the decryption stage is given the output of the
encryption stage as input. The result is checked against the original
plaintext. For this to give the correct results the crypto objects
are reset for each iteration of the benchmark. In addition, the size
of the plain text has been increased a little and the use of
Math.random() and new Date() to build an RNG pool has been
removed. </p>
<p>Other benchmarks were fixed to do elementary verification of the
results of their calculations. This is to avoid accidentally
obtaining scores that are the result of an incorrect JavaScript engine
optimization.</p>
</td><td style="text-align: center">
<div class="run">
<div id="status" style="text-align: center; margin-top: 75px; font-size: 120%; font-weight: bold;">Starting...</div>
<div style="text-align: left; margin: 30px 0 0 90px;" id="results">
<div>
</div>
</td></tr></table>
</div>
</body>
</html>

View File

@ -1,59 +0,0 @@
// Copyright 2008 the V8 project 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.
load('base.js');
load('richards.js');
load('deltablue.js');
load('crypto.js');
load('raytrace.js');
load('earley-boyer.js');
var success = true;
function PrintResult(name, result) {
print(name + ': ' + result);
}
function PrintError(name, error) {
PrintResult(name, error);
success = false;
}
function PrintScore(score) {
if (success) {
print('----');
print('Score (version ' + BenchmarkSuite.version + '): ' + score);
}
}
BenchmarkSuite.RunSuites({ NotifyResult: PrintResult,
NotifyError: PrintError,
NotifyScore: PrintScore });

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

View File

@ -1,143 +0,0 @@
// Copyright 2008 the V8 project 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.
#ifndef V8_DEBUG_H_
#define V8_DEBUG_H_
#include "v8.h"
#ifdef _WIN32
typedef int int32_t;
typedef unsigned int uint32_t;
typedef unsigned short uint16_t; // NOLINT
typedef long long int64_t; // NOLINT
// Setup for Windows DLL export/import. See v8.h in this directory for
// information on how to build/use V8 as a DLL.
#if defined(BUILDING_V8_SHARED) && defined(USING_V8_SHARED)
#error both BUILDING_V8_SHARED and USING_V8_SHARED are set - please check the\
build configuration to ensure that at most one of these is set
#endif
#ifdef BUILDING_V8_SHARED
#define EXPORT __declspec(dllexport)
#elif USING_V8_SHARED
#define EXPORT __declspec(dllimport)
#else
#define EXPORT
#endif
#else // _WIN32
// Setup for Linux shared library export. See v8.h in this directory for
// information on how to build/use V8 as shared library.
#if defined(__GNUC__) && (__GNUC__ >= 4)
#define EXPORT __attribute__ ((visibility("default")))
#else // defined(__GNUC__) && (__GNUC__ >= 4)
#define EXPORT
#endif // defined(__GNUC__) && (__GNUC__ >= 4)
#endif // _WIN32
/**
* Debugger support for the V8 JavaScript engine.
*/
namespace v8 {
// Debug events which can occur in the V8 JavaScript engine.
enum DebugEvent {
Break = 1,
Exception = 2,
NewFunction = 3,
BeforeCompile = 4,
AfterCompile = 5
};
/**
* Debug event callback function.
*
* \param event the debug event from which occoured (from the DebugEvent
* enumeration)
* \param exec_state execution state (JavaScript object)
* \param event_data event specific data (JavaScript object)
* \param data value passed by the user to AddDebugEventListener
*/
typedef void (*DebugEventCallback)(DebugEvent event,
Handle<Object> exec_state,
Handle<Object> event_data,
Handle<Value> data);
/**
* Debug message callback function.
*
* \param message the debug message
* \param length length of the message
* A DebugMessageHandler does not take posession of the message string,
* and must not rely on the data persisting after the handler returns.
*/
typedef void (*DebugMessageHandler)(const uint16_t* message, int length,
void* data);
class EXPORT Debug {
public:
// Add a C debug event listener.
static bool AddDebugEventListener(DebugEventCallback that,
Handle<Value> data = Handle<Value>());
// Add a JavaScript debug event listener.
static bool AddDebugEventListener(v8::Handle<v8::Function> that,
Handle<Value> data = Handle<Value>());
// Remove a C debug event listener.
static void RemoveDebugEventListener(DebugEventCallback that);
// Remove a JavaScript debug event listener.
static void RemoveDebugEventListener(v8::Handle<v8::Function> that);
// Generate a stack dump.
static void StackDump();
// Break execution of JavaScript.
static void DebugBreak();
// Message based interface. The message protocol is JSON.
static void SetMessageHandler(DebugMessageHandler handler, void* data = NULL);
static void SendCommand(const uint16_t* command, int length);
};
} // namespace v8
#undef EXPORT
#endif // V8_DEBUG_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,38 +0,0 @@
# Copyright 2008 the V8 project 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.
from os.path import join
Import('sample context')
def ConfigureObjectFiles():
env = Environment()
env.Replace(**context.flags['sample'])
context.ApplyEnvOverrides(env)
return env.Object(sample + '.cc')
sample_object = ConfigureObjectFiles()
Return('sample_object')

View File

@ -1,42 +0,0 @@
// Copyright 2008 the V8 project 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.
function Initialize() { }
function Process(request) {
if (options.verbose) {
log("Processing " + request.host + request.path +
" from " + request.referrer + "@" + request.userAgent);
}
if (!output[request.host]) {
output[request.host] = 1;
} else {
output[request.host]++
}
}
Initialize();

View File

@ -1,624 +0,0 @@
// Copyright 2008 the V8 project 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.
#include <v8.h>
// To avoid warnings from <map> on windows we disable exceptions.
#define _HAS_EXCEPTIONS 0
#include <string>
#include <map>
using namespace std;
using namespace v8;
// These interfaces represent an existing request processing interface.
// The idea is to imagine a real application that uses these interfaces
// and then add scripting capabilities that allow you to interact with
// the objects through JavaScript.
/**
* A simplified http request.
*/
class HttpRequest {
public:
virtual ~HttpRequest() { }
virtual const string& Path() = 0;
virtual const string& Referrer() = 0;
virtual const string& Host() = 0;
virtual const string& UserAgent() = 0;
};
/**
* The abstract superclass of http request processors.
*/
class HttpRequestProcessor {
public:
virtual ~HttpRequestProcessor() { }
// Initialize this processor. The map contains options that control
// how requests should be processed.
virtual bool Initialize(map<string, string>* options,
map<string, string>* output) = 0;
// Process a single request.
virtual bool Process(HttpRequest* req) = 0;
static void Log(const char* event);
};
/**
* An http request processor that is scriptable using JavaScript.
*/
class JsHttpRequestProcessor : public HttpRequestProcessor {
public:
// Creates a new processor that processes requests by invoking the
// Process function of the JavaScript script given as an argument.
explicit JsHttpRequestProcessor(Handle<String> script) : script_(script) { }
virtual ~JsHttpRequestProcessor();
virtual bool Initialize(map<string, string>* opts,
map<string, string>* output);
virtual bool Process(HttpRequest* req);
private:
// Execute the script associated with this processor and extract the
// Process function. Returns true if this succeeded, otherwise false.
bool ExecuteScript(Handle<String> script);
// Wrap the options and output map in a JavaScript objects and
// install it in the global namespace as 'options' and 'output'.
bool InstallMaps(map<string, string>* opts, map<string, string>* output);
// Constructs the template that describes the JavaScript wrapper
// type for requests.
static Handle<ObjectTemplate> MakeRequestTemplate();
static Handle<ObjectTemplate> MakeMapTemplate();
// Callbacks that access the individual fields of request objects.
static Handle<Value> GetPath(Local<String> name, const AccessorInfo& info);
static Handle<Value> GetReferrer(Local<String> name,
const AccessorInfo& info);
static Handle<Value> GetHost(Local<String> name, const AccessorInfo& info);
static Handle<Value> GetUserAgent(Local<String> name,
const AccessorInfo& info);
// Callbacks that access maps
static Handle<Value> MapGet(Local<String> name, const AccessorInfo& info);
static Handle<Value> MapSet(Local<String> name,
Local<Value> value,
const AccessorInfo& info);
// Utility methods for wrapping C++ objects as JavaScript objects,
// and going back again.
static Handle<Object> WrapMap(map<string, string>* obj);
static map<string, string>* UnwrapMap(Handle<Object> obj);
static Handle<Object> WrapRequest(HttpRequest* obj);
static HttpRequest* UnwrapRequest(Handle<Object> obj);
Handle<String> script_;
Persistent<Context> context_;
Persistent<Function> process_;
static Persistent<ObjectTemplate> request_template_;
static Persistent<ObjectTemplate> map_template_;
};
// -------------------------
// --- P r o c e s s o r ---
// -------------------------
static Handle<Value> LogCallback(const Arguments& args) {
if (args.Length() < 1) return v8::Undefined();
HandleScope scope;
Handle<Value> arg = args[0];
String::Utf8Value value(arg);
HttpRequestProcessor::Log(*value);
return v8::Undefined();
}
// Execute the script and fetch the Process method.
bool JsHttpRequestProcessor::Initialize(map<string, string>* opts,
map<string, string>* output) {
// Create a handle scope to hold the temporary references.
HandleScope handle_scope;
// Create a template for the global object where we set the
// built-in global functions.
Handle<ObjectTemplate> global = ObjectTemplate::New();
global->Set(String::New("log"), FunctionTemplate::New(LogCallback));
// Each processor gets its own context so different processors
// don't affect each other (ignore the first three lines).
Handle<Context> context = Context::New(NULL, global);
// Store the context in the processor object in a persistent handle,
// since we want the reference to remain after we return from this
// method.
context_ = Persistent<Context>::New(context);
// Enter the new context so all the following operations take place
// within it.
Context::Scope context_scope(context);
// Make the options mapping available within the context
if (!InstallMaps(opts, output))
return false;
// Compile and run the script
if (!ExecuteScript(script_))
return false;
// The script compiled and ran correctly. Now we fetch out the
// Process function from the global object.
Handle<String> process_name = String::New("Process");
Handle<Value> process_val = context->Global()->Get(process_name);
// If there is no Process function, or if it is not a function,
// bail out
if (!process_val->IsFunction()) return false;
// It is a function; cast it to a Function
Handle<Function> process_fun = Handle<Function>::Cast(process_val);
// Store the function in a Persistent handle, since we also want
// that to remain after this call returns
process_ = Persistent<Function>::New(process_fun);
// All done; all went well
return true;
}
bool JsHttpRequestProcessor::ExecuteScript(Handle<String> script) {
HandleScope handle_scope;
// We're just about to compile the script; set up an error handler to
// catch any exceptions the script might throw.
TryCatch try_catch;
// Compile the script and check for errors.
Handle<Script> compiled_script = Script::Compile(script);
if (compiled_script.IsEmpty()) {
String::Utf8Value error(try_catch.Exception());
Log(*error);
// The script failed to compile; bail out.
return false;
}
// Run the script!
Handle<Value> result = compiled_script->Run();
if (result.IsEmpty()) {
// The TryCatch above is still in effect and will have caught the error.
String::Utf8Value error(try_catch.Exception());
Log(*error);
// Running the script failed; bail out.
return false;
}
return true;
}
bool JsHttpRequestProcessor::InstallMaps(map<string, string>* opts,
map<string, string>* output) {
HandleScope handle_scope;
// Wrap the map object in a JavaScript wrapper
Handle<Object> opts_obj = WrapMap(opts);
// Set the options object as a property on the global object.
context_->Global()->Set(String::New("options"), opts_obj);
Handle<Object> output_obj = WrapMap(output);
context_->Global()->Set(String::New("output"), output_obj);
return true;
}
bool JsHttpRequestProcessor::Process(HttpRequest* request) {
// Create a handle scope to keep the temporary object references.
HandleScope handle_scope;
// Enter this processor's context so all the remaining operations
// take place there
Context::Scope context_scope(context_);
// Wrap the C++ request object in a JavaScript wrapper
Handle<Object> request_obj = WrapRequest(request);
// Set up an exception handler before calling the Process function
TryCatch try_catch;
// Invoke the process function, giving the global object as 'this'
// and one argument, the request.
const int argc = 1;
Handle<Value> argv[argc] = { request_obj };
Handle<Value> result = process_->Call(context_->Global(), argc, argv);
if (result.IsEmpty()) {
String::Utf8Value error(try_catch.Exception());
Log(*error);
return false;
} else {
return true;
}
}
JsHttpRequestProcessor::~JsHttpRequestProcessor() {
// Dispose the persistent handles. When noone else has any
// references to the objects stored in the handles they will be
// automatically reclaimed.
context_.Dispose();
process_.Dispose();
}
Persistent<ObjectTemplate> JsHttpRequestProcessor::request_template_;
Persistent<ObjectTemplate> JsHttpRequestProcessor::map_template_;
// -----------------------------------
// --- A c c e s s i n g M a p s ---
// -----------------------------------
// Utility function that wraps a C++ http request object in a
// JavaScript object.
Handle<Object> JsHttpRequestProcessor::WrapMap(map<string, string>* obj) {
// Handle scope for temporary handles.
HandleScope handle_scope;
// Fetch the template for creating JavaScript map wrappers.
// It only has to be created once, which we do on demand.
if (request_template_.IsEmpty()) {
Handle<ObjectTemplate> raw_template = MakeMapTemplate();
map_template_ = Persistent<ObjectTemplate>::New(raw_template);
}
Handle<ObjectTemplate> templ = map_template_;
// Create an empty map wrapper.
Handle<Object> result = templ->NewInstance();
// Wrap the raw C++ pointer in an External so it can be referenced
// from within JavaScript.
Handle<External> map_ptr = External::New(obj);
// Store the map pointer in the JavaScript wrapper.
result->SetInternalField(0, map_ptr);
// Return the result through the current handle scope. Since each
// of these handles will go away when the handle scope is deleted
// we need to call Close to let one, the result, escape into the
// outer handle scope.
return handle_scope.Close(result);
}
// Utility function that extracts the C++ map pointer from a wrapper
// object.
map<string, string>* JsHttpRequestProcessor::UnwrapMap(Handle<Object> obj) {
Handle<External> field = Handle<External>::Cast(obj->GetInternalField(0));
void* ptr = field->Value();
return static_cast<map<string, string>*>(ptr);
}
// Convert a JavaScript string to a std::string. To not bother too
// much with string encodings we just use ascii.
string ObjectToString(Local<Value> value) {
String::Utf8Value utf8_value(value);
return string(*utf8_value);
}
Handle<Value> JsHttpRequestProcessor::MapGet(Local<String> name,
const AccessorInfo& info) {
// Fetch the map wrapped by this object.
map<string, string>* obj = UnwrapMap(info.Holder());
// Convert the JavaScript string to a std::string.
string key = ObjectToString(name);
// Look up the value if it exists using the standard STL ideom.
map<string, string>::iterator iter = obj->find(key);
// If the key is not present return an empty handle as signal
if (iter == obj->end()) return Handle<Value>();
// Otherwise fetch the value and wrap it in a JavaScript string
const string& value = (*iter).second;
return String::New(value.c_str(), value.length());
}
Handle<Value> JsHttpRequestProcessor::MapSet(Local<String> name,
Local<Value> value_obj,
const AccessorInfo& info) {
// Fetch the map wrapped by this object.
map<string, string>* obj = UnwrapMap(info.Holder());
// Convert the key and value to std::strings.
string key = ObjectToString(name);
string value = ObjectToString(value_obj);
// Update the map.
(*obj)[key] = value;
// Return the value; any non-empty handle will work.
return value_obj;
}
Handle<ObjectTemplate> JsHttpRequestProcessor::MakeMapTemplate() {
HandleScope handle_scope;
Handle<ObjectTemplate> result = ObjectTemplate::New();
result->SetInternalFieldCount(1);
result->SetNamedPropertyHandler(MapGet, MapSet);
// Again, return the result through the current handle scope.
return handle_scope.Close(result);
}
// -------------------------------------------
// --- A c c e s s i n g R e q u e s t s ---
// -------------------------------------------
/**
* Utility function that wraps a C++ http request object in a
* JavaScript object.
*/
Handle<Object> JsHttpRequestProcessor::WrapRequest(HttpRequest* request) {
// Handle scope for temporary handles.
HandleScope handle_scope;
// Fetch the template for creating JavaScript http request wrappers.
// It only has to be created once, which we do on demand.
if (request_template_.IsEmpty()) {
Handle<ObjectTemplate> raw_template = MakeRequestTemplate();
request_template_ = Persistent<ObjectTemplate>::New(raw_template);
}
Handle<ObjectTemplate> templ = request_template_;
// Create an empty http request wrapper.
Handle<Object> result = templ->NewInstance();
// Wrap the raw C++ pointer in an External so it can be referenced
// from within JavaScript.
Handle<External> request_ptr = External::New(request);
// Store the request pointer in the JavaScript wrapper.
result->SetInternalField(0, request_ptr);
// Return the result through the current handle scope. Since each
// of these handles will go away when the handle scope is deleted
// we need to call Close to let one, the result, escape into the
// outer handle scope.
return handle_scope.Close(result);
}
/**
* Utility function that extracts the C++ http request object from a
* wrapper object.
*/
HttpRequest* JsHttpRequestProcessor::UnwrapRequest(Handle<Object> obj) {
Handle<External> field = Handle<External>::Cast(obj->GetInternalField(0));
void* ptr = field->Value();
return static_cast<HttpRequest*>(ptr);
}
Handle<Value> JsHttpRequestProcessor::GetPath(Local<String> name,
const AccessorInfo& info) {
// Extract the C++ request object from the JavaScript wrapper.
HttpRequest* request = UnwrapRequest(info.Holder());
// Fetch the path.
const string& path = request->Path();
// Wrap the result in a JavaScript string and return it.
return String::New(path.c_str(), path.length());
}
Handle<Value> JsHttpRequestProcessor::GetReferrer(Local<String> name,
const AccessorInfo& info) {
HttpRequest* request = UnwrapRequest(info.Holder());
const string& path = request->Referrer();
return String::New(path.c_str(), path.length());
}
Handle<Value> JsHttpRequestProcessor::GetHost(Local<String> name,
const AccessorInfo& info) {
HttpRequest* request = UnwrapRequest(info.Holder());
const string& path = request->Host();
return String::New(path.c_str(), path.length());
}
Handle<Value> JsHttpRequestProcessor::GetUserAgent(Local<String> name,
const AccessorInfo& info) {
HttpRequest* request = UnwrapRequest(info.Holder());
const string& path = request->UserAgent();
return String::New(path.c_str(), path.length());
}
Handle<ObjectTemplate> JsHttpRequestProcessor::MakeRequestTemplate() {
HandleScope handle_scope;
Handle<ObjectTemplate> result = ObjectTemplate::New();
result->SetInternalFieldCount(1);
// Add accessors for each of the fields of the request.
result->SetAccessor(String::NewSymbol("path"), GetPath);
result->SetAccessor(String::NewSymbol("referrer"), GetReferrer);
result->SetAccessor(String::NewSymbol("host"), GetHost);
result->SetAccessor(String::NewSymbol("userAgent"), GetUserAgent);
// Again, return the result through the current handle scope.
return handle_scope.Close(result);
}
// --- Test ---
void HttpRequestProcessor::Log(const char* event) {
printf("Logged: %s\n", event);
}
/**
* A simplified http request.
*/
class StringHttpRequest : public HttpRequest {
public:
StringHttpRequest(const string& path,
const string& referrer,
const string& host,
const string& user_agent);
virtual const string& Path() { return path_; }
virtual const string& Referrer() { return referrer_; }
virtual const string& Host() { return host_; }
virtual const string& UserAgent() { return user_agent_; }
private:
string path_;
string referrer_;
string host_;
string user_agent_;
};
StringHttpRequest::StringHttpRequest(const string& path,
const string& referrer,
const string& host,
const string& user_agent)
: path_(path),
referrer_(referrer),
host_(host),
user_agent_(user_agent) { }
void ParseOptions(int argc,
char* argv[],
map<string, string>& options,
string* file) {
for (int i = 1; i < argc; i++) {
string arg = argv[i];
int index = arg.find('=', 0);
if (index == string::npos) {
*file = arg;
} else {
string key = arg.substr(0, index);
string value = arg.substr(index+1);
options[key] = value;
}
}
}
// Reads a file into a v8 string.
Handle<String> ReadFile(const string& name) {
FILE* file = fopen(name.c_str(), "rb");
if (file == NULL) return Handle<String>();
fseek(file, 0, SEEK_END);
int size = ftell(file);
rewind(file);
char* chars = new char[size + 1];
chars[size] = '\0';
for (int i = 0; i < size;) {
int read = fread(&chars[i], 1, size - i, file);
i += read;
}
fclose(file);
Handle<String> result = String::New(chars, size);
delete[] chars;
return result;
}
const int kSampleSize = 6;
StringHttpRequest kSampleRequests[kSampleSize] = {
StringHttpRequest("/process.cc", "localhost", "google.com", "firefox"),
StringHttpRequest("/", "localhost", "google.net", "firefox"),
StringHttpRequest("/", "localhost", "google.org", "safari"),
StringHttpRequest("/", "localhost", "yahoo.com", "ie"),
StringHttpRequest("/", "localhost", "yahoo.com", "safari"),
StringHttpRequest("/", "localhost", "yahoo.com", "firefox")
};
bool ProcessEntries(HttpRequestProcessor* processor, int count,
StringHttpRequest* reqs) {
for (int i = 0; i < count; i++) {
if (!processor->Process(&reqs[i]))
return false;
}
return true;
}
void PrintMap(map<string, string>* m) {
for (map<string, string>::iterator i = m->begin(); i != m->end(); i++) {
pair<string, string> entry = *i;
printf("%s: %s\n", entry.first.c_str(), entry.second.c_str());
}
}
int main(int argc, char* argv[]) {
map<string, string> options;
string file;
ParseOptions(argc, argv, options, &file);
if (file.empty()) {
fprintf(stderr, "No script was specified.\n");
return 1;
}
HandleScope scope;
Handle<String> source = ReadFile(file);
if (source.IsEmpty()) {
fprintf(stderr, "Error reading '%s'.\n", file.c_str());
return 1;
}
JsHttpRequestProcessor processor(source);
map<string, string> output;
if (!processor.Initialize(&options, &output)) {
fprintf(stderr, "Error initializing processor.\n");
return 1;
}
if (!ProcessEntries(&processor, kSampleSize, kSampleRequests))
return 1;
PrintMap(&output);
}

View File

@ -1,258 +0,0 @@
// Copyright 2008 the V8 project 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.
#include <v8.h>
#include <cstring>
#include <cstdio>
#include <cstdlib>
void RunShell(v8::Handle<v8::Context> context);
bool ExecuteString(v8::Handle<v8::String> source,
v8::Handle<v8::Value> name,
bool print_result,
bool report_exceptions);
v8::Handle<v8::Value> Print(const v8::Arguments& args);
v8::Handle<v8::Value> Load(const v8::Arguments& args);
v8::Handle<v8::Value> Quit(const v8::Arguments& args);
v8::Handle<v8::Value> Version(const v8::Arguments& args);
v8::Handle<v8::String> ReadFile(const char* name);
void ReportException(v8::TryCatch* handler);
int main(int argc, char* argv[]) {
v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
v8::HandleScope handle_scope;
// Create a template for the global object.
v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
// Bind the global 'print' function to the C++ Print callback.
global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print));
// Bind the global 'load' function to the C++ Load callback.
global->Set(v8::String::New("load"), v8::FunctionTemplate::New(Load));
// Bind the 'quit' function
global->Set(v8::String::New("quit"), v8::FunctionTemplate::New(Quit));
// Bind the 'version' function
global->Set(v8::String::New("version"), v8::FunctionTemplate::New(Version));
// Create a new execution environment containing the built-in
// functions
v8::Handle<v8::Context> context = v8::Context::New(NULL, global);
// Enter the newly created execution environment.
v8::Context::Scope context_scope(context);
bool run_shell = (argc == 1);
for (int i = 1; i < argc; i++) {
const char* str = argv[i];
if (strcmp(str, "--shell") == 0) {
run_shell = true;
} else if (strcmp(str, "-f") == 0) {
// Ignore any -f flags for compatibility with the other stand-
// alone JavaScript engines.
continue;
} else if (strncmp(str, "--", 2) == 0) {
printf("Warning: unknown flag %s.\n", str);
} else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
// Execute argument given to -e option directly
v8::HandleScope handle_scope;
v8::Handle<v8::String> file_name = v8::String::New("unnamed");
v8::Handle<v8::String> source = v8::String::New(argv[i + 1]);
if (!ExecuteString(source, file_name, false, true))
return 1;
i++;
} else {
// Use all other arguments as names of files to load and run.
v8::HandleScope handle_scope;
v8::Handle<v8::String> file_name = v8::String::New(str);
v8::Handle<v8::String> source = ReadFile(str);
if (source.IsEmpty()) {
printf("Error reading '%s'\n", str);
return 1;
}
if (!ExecuteString(source, file_name, false, true))
return 1;
}
}
if (run_shell) RunShell(context);
return 0;
}
// The callback that is invoked by v8 whenever the JavaScript 'print'
// function is called. Prints its arguments on stdout separated by
// spaces and ending with a newline.
v8::Handle<v8::Value> Print(const v8::Arguments& args) {
bool first = true;
for (int i = 0; i < args.Length(); i++) {
v8::HandleScope handle_scope;
if (first) {
first = false;
} else {
printf(" ");
}
v8::String::Utf8Value str(args[i]);
printf("%s", *str);
}
printf("\n");
return v8::Undefined();
}
// The callback that is invoked by v8 whenever the JavaScript 'load'
// function is called. Loads, compiles and executes its argument
// JavaScript file.
v8::Handle<v8::Value> Load(const v8::Arguments& args) {
for (int i = 0; i < args.Length(); i++) {
v8::HandleScope handle_scope;
v8::String::Utf8Value file(args[i]);
v8::Handle<v8::String> source = ReadFile(*file);
if (source.IsEmpty()) {
return v8::ThrowException(v8::String::New("Error loading file"));
}
if (!ExecuteString(source, v8::String::New(*file), false, false)) {
return v8::ThrowException(v8::String::New("Error executing file"));
}
}
return v8::Undefined();
}
// The callback that is invoked by v8 whenever the JavaScript 'quit'
// function is called. Quits.
v8::Handle<v8::Value> Quit(const v8::Arguments& args) {
// If not arguments are given args[0] will yield undefined which
// converts to the integer value 0.
int exit_code = args[0]->Int32Value();
exit(exit_code);
return v8::Undefined();
}
v8::Handle<v8::Value> Version(const v8::Arguments& args) {
return v8::String::New(v8::V8::GetVersion());
}
// Reads a file into a v8 string.
v8::Handle<v8::String> ReadFile(const char* name) {
FILE* file = fopen(name, "rb");
if (file == NULL) return v8::Handle<v8::String>();
fseek(file, 0, SEEK_END);
int size = ftell(file);
rewind(file);
char* chars = new char[size + 1];
chars[size] = '\0';
for (int i = 0; i < size;) {
int read = fread(&chars[i], 1, size - i, file);
i += read;
}
fclose(file);
v8::Handle<v8::String> result = v8::String::New(chars, size);
delete[] chars;
return result;
}
// The read-eval-execute loop of the shell.
void RunShell(v8::Handle<v8::Context> context) {
printf("V8 version %s\n", v8::V8::GetVersion());
static const int kBufferSize = 256;
while (true) {
char buffer[kBufferSize];
printf("> ");
char* str = fgets(buffer, kBufferSize, stdin);
if (str == NULL) break;
v8::HandleScope handle_scope;
ExecuteString(v8::String::New(str),
v8::String::New("(shell)"),
true,
true);
}
printf("\n");
}
// Executes a string within the current v8 context.
bool ExecuteString(v8::Handle<v8::String> source,
v8::Handle<v8::Value> name,
bool print_result,
bool report_exceptions) {
v8::HandleScope handle_scope;
v8::TryCatch try_catch;
v8::Handle<v8::Script> script = v8::Script::Compile(source, name);
if (script.IsEmpty()) {
// Print errors that happened during compilation.
if (report_exceptions)
ReportException(&try_catch);
return false;
} else {
v8::Handle<v8::Value> result = script->Run();
if (result.IsEmpty()) {
// Print errors that happened during execution.
if (report_exceptions)
ReportException(&try_catch);
return false;
} else {
if (print_result && !result->IsUndefined()) {
// If all went well and the result wasn't undefined then print
// the returned value.
v8::String::Utf8Value str(result);
printf("%s\n", *str);
}
return true;
}
}
}
void ReportException(v8::TryCatch* try_catch) {
v8::HandleScope handle_scope;
v8::String::Utf8Value exception(try_catch->Exception());
v8::Handle<v8::Message> message = try_catch->Message();
if (message.IsEmpty()) {
// V8 didn't provide any extra information about this error; just
// print the exception.
printf("%s\n", *exception);
} else {
// Print (filename):(line number): (message).
v8::String::Utf8Value filename(message->GetScriptResourceName());
int linenum = message->GetLineNumber();
printf("%s:%i: %s\n", *filename, linenum, *exception);
// Print line of source code.
v8::String::Utf8Value sourceline(message->GetSourceLine());
printf("%s\n", *sourceline);
// Print wavy underline (GetUnderline is deprecated).
int start = message->GetStartColumn();
for (int i = 0; i < start; i++) {
printf(" ");
}
int end = message->GetEndColumn();
for (int i = start; i < end; i++) {
printf("^");
}
printf("\n");
}
}

View File

@ -1,160 +0,0 @@
# Copyright 2008 the V8 project 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.
import sys
from os.path import join, dirname, abspath
root_dir = dirname(File('SConstruct').rfile().abspath)
sys.path.append(join(root_dir, 'tools'))
import js2c
Import('context')
SOURCES = {
'all': [
'accessors.cc', 'allocation.cc', 'api.cc', 'assembler.cc', 'ast.cc',
'bootstrapper.cc', 'builtins.cc', 'checks.cc', 'code-stubs.cc',
'codegen.cc', 'compilation-cache.cc', 'compiler.cc', 'contexts.cc',
'conversions.cc', 'counters.cc', 'dateparser.cc', 'debug.cc',
'disassembler.cc', 'execution.cc', 'factory.cc', 'flags.cc', 'frames.cc',
'global-handles.cc', 'handles.cc', 'hashmap.cc', 'heap.cc', 'ic.cc',
'jsregexp.cc', 'log.cc', 'mark-compact.cc', 'messages.cc', 'objects.cc',
'parser.cc', 'property.cc', 'rewriter.cc', 'runtime.cc', 'scanner.cc',
'scopeinfo.cc', 'scopes.cc', 'serialize.cc', 'snapshot-common.cc',
'spaces.cc', 'string-stream.cc', 'stub-cache.cc', 'token.cc', 'top.cc',
'unicode.cc', 'usage-analyzer.cc', 'utils.cc', 'v8-counters.cc',
'v8.cc', 'v8threads.cc', 'variables.cc', 'zone.cc'
],
'arch:arm': ['assembler-arm.cc', 'builtins-arm.cc', 'codegen-arm.cc',
'cpu-arm.cc', 'disasm-arm.cc', 'frames-arm.cc', 'ic-arm.cc',
'macro-assembler-arm.cc', 'stub-cache-arm.cc'],
'arch:ia32': ['assembler-ia32.cc', 'builtins-ia32.cc', 'codegen-ia32.cc',
'cpu-ia32.cc', 'disasm-ia32.cc', 'frames-ia32.cc', 'ic-ia32.cc',
'macro-assembler-ia32.cc', 'stub-cache-ia32.cc'],
'simulator:arm': ['simulator-arm.cc'],
'os:linux': ['platform-linux.cc'],
'os:macos': ['platform-macos.cc'],
'os:nullos': ['platform-nullos.cc'],
'os:win32': ['platform-win32.cc'],
'mode:release': [],
'mode:debug': ['objects-debug.cc', 'prettyprinter.cc']
}
D8_FILES = {
'all': [
'd8.cc'
],
'console:readline': [
'd8-readline.cc'
]
}
LIBRARY_FILES = '''
runtime.js
v8natives.js
array.js
string.js
uri.js
math.js
messages.js
apinatives.js
debug-delay.js
mirror-delay.js
date-delay.js
regexp-delay.js
'''.split()
JSCRE_FILES = '''
pcre_compile.cpp
pcre_exec.cpp
pcre_tables.cpp
pcre_ucp_searchfuncs.cpp
pcre_xclass.cpp
'''.split()
def Abort(message):
print message
sys.exit(1)
def ConfigureObjectFiles():
env = Environment()
env.Replace(**context.flags['v8'])
context.ApplyEnvOverrides(env)
env['BUILDERS']['JS2C'] = Builder(action=js2c.JS2C)
env['BUILDERS']['Snapshot'] = Builder(action='$SOURCE $TARGET --logfile "$LOGFILE"')
# Build the standard platform-independent source files.
source_files = context.GetRelevantSources(SOURCES)
d8_files = context.GetRelevantSources(D8_FILES)
d8_js = env.JS2C('d8-js.cc', 'd8.js', TYPE='D8')
d8_js_obj = context.ConfigureObject(env, d8_js, CPPPATH=['.'])
d8_objs = [context.ConfigureObject(env, [d8_files]), d8_js_obj]
# Combine the JavaScript library files into a single C++ file and
# compile it.
library_files = [s for s in LIBRARY_FILES]
library_files.append('macros.py')
libraries_src, libraries_empty_src = env.JS2C(['libraries.cc', 'libraries-empty.cc'], library_files, TYPE='CORE')
libraries_obj = context.ConfigureObject(env, libraries_src, CPPPATH=['.'])
# Build JSCRE.
jscre_env = env.Copy()
jscre_env.Replace(**context.flags['jscre'])
jscre_files = [join('third_party', 'jscre', s) for s in JSCRE_FILES]
jscre_obj = context.ConfigureObject(jscre_env, jscre_files)
# Build dtoa.
dtoa_env = env.Copy()
dtoa_env.Replace(**context.flags['dtoa'])
dtoa_files = ['dtoa-config.c']
dtoa_obj = context.ConfigureObject(dtoa_env, dtoa_files)
source_objs = context.ConfigureObject(env, source_files)
non_snapshot_files = [jscre_obj, dtoa_obj, source_objs]
# Create snapshot if necessary.
empty_snapshot_obj = context.ConfigureObject(env, 'snapshot-empty.cc')
if context.use_snapshot:
mksnapshot_src = 'mksnapshot.cc'
mksnapshot = env.Program('mksnapshot', [mksnapshot_src, libraries_obj, non_snapshot_files, empty_snapshot_obj], PDB='mksnapshot.exe.pdb')
snapshot_cc = env.Snapshot('snapshot.cc', mksnapshot, LOGFILE=File('snapshot.log').abspath)
snapshot_obj = context.ConfigureObject(env, snapshot_cc, CPPPATH=['.'])
libraries_obj = context.ConfigureObject(env, libraries_empty_src, CPPPATH=['.'])
else:
snapshot_obj = empty_snapshot_obj
library_objs = [non_snapshot_files, libraries_obj, snapshot_obj]
return (library_objs, d8_objs)
(library_objs, d8_objs) = ConfigureObjectFiles()
Return('library_objs d8_objs')

View File

@ -1,510 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#include "v8.h"
#include "accessors.h"
#include "execution.h"
#include "factory.h"
#include "scopeinfo.h"
#include "top.h"
#include "zone-inl.h"
namespace v8 { namespace internal {
template <class C>
static C* FindInPrototypeChain(Object* obj, bool* found_it) {
ASSERT(!*found_it);
while (!Is<C>(obj)) {
if (obj == Heap::null_value()) return NULL;
obj = obj->GetPrototype();
}
*found_it = true;
return C::cast(obj);
}
// Entry point that never should be called.
Object* Accessors::IllegalSetter(JSObject*, Object*, void*) {
UNREACHABLE();
return NULL;
}
Object* Accessors::IllegalGetAccessor(Object* object, void*) {
UNREACHABLE();
return object;
}
Object* Accessors::ReadOnlySetAccessor(JSObject*, Object* value, void*) {
// According to ECMA-262, section 8.6.2.2, page 28, setting
// read-only properties must be silently ignored.
return value;
}
//
// Accessors::ArrayLength
//
Object* Accessors::ArrayGetLength(Object* object, void*) {
// Traverse the prototype chain until we reach an array.
bool found_it = false;
JSArray* holder = FindInPrototypeChain<JSArray>(object, &found_it);
if (!found_it) return Smi::FromInt(0);
return holder->length();
}
// The helper function will 'flatten' Number objects.
Object* Accessors::FlattenNumber(Object* value) {
if (value->IsNumber() || !value->IsJSValue()) return value;
JSValue* wrapper = JSValue::cast(value);
ASSERT(
Top::context()->global_context()->number_function()->has_initial_map());
Map* number_map =
Top::context()->global_context()->number_function()->initial_map();
if (wrapper->map() == number_map) return wrapper->value();
return value;
}
Object* Accessors::ArraySetLength(JSObject* object, Object* value, void*) {
value = FlattenNumber(value);
// Need to call methods that may trigger GC.
HandleScope scope;
// Protect raw pointers.
Handle<JSObject> object_handle(object);
Handle<Object> value_handle(value);
bool has_exception;
Handle<Object> uint32_v = Execution::ToUint32(value_handle, &has_exception);
if (has_exception) return Failure::Exception();
Handle<Object> number_v = Execution::ToNumber(value_handle, &has_exception);
if (has_exception) return Failure::Exception();
// Restore raw pointers,
object = *object_handle;
value = *value_handle;
if (uint32_v->Number() == number_v->Number()) {
if (object->IsJSArray()) {
return JSArray::cast(object)->SetElementsLength(*uint32_v);
} else {
// This means one of the object's prototypes is a JSArray and
// the object does not have a 'length' property.
// Calling SetProperty causes an infinite loop.
return object->IgnoreAttributesAndSetLocalProperty(Heap::length_symbol(),
value, NONE);
}
}
return Top::Throw(*Factory::NewRangeError("invalid_array_length",
HandleVector<Object>(NULL, 0)));
}
const AccessorDescriptor Accessors::ArrayLength = {
ArrayGetLength,
ArraySetLength,
0
};
//
// Accessors::StringLength
//
Object* Accessors::StringGetLength(Object* object, void*) {
Object* value = object;
if (object->IsJSValue()) value = JSValue::cast(object)->value();
if (value->IsString()) return Smi::FromInt(String::cast(value)->length());
// If object is not a string we return 0 to be compatible with WebKit.
// Note: Firefox returns the length of ToString(object).
return Smi::FromInt(0);
}
const AccessorDescriptor Accessors::StringLength = {
StringGetLength,
IllegalSetter,
0
};
//
// Accessors::ScriptSource
//
Object* Accessors::ScriptGetSource(Object* object, void*) {
Object* script = JSValue::cast(object)->value();
return Script::cast(script)->source();
}
const AccessorDescriptor Accessors::ScriptSource = {
ScriptGetSource,
IllegalSetter,
0
};
//
// Accessors::ScriptName
//
Object* Accessors::ScriptGetName(Object* object, void*) {
Object* script = JSValue::cast(object)->value();
return Script::cast(script)->name();
}
const AccessorDescriptor Accessors::ScriptName = {
ScriptGetName,
IllegalSetter,
0
};
//
// Accessors::ScriptLineOffset
//
Object* Accessors::ScriptGetLineOffset(Object* object, void*) {
Object* script = JSValue::cast(object)->value();
return Script::cast(script)->line_offset();
}
const AccessorDescriptor Accessors::ScriptLineOffset = {
ScriptGetLineOffset,
IllegalSetter,
0
};
//
// Accessors::ScriptColumnOffset
//
Object* Accessors::ScriptGetColumnOffset(Object* object, void*) {
Object* script = JSValue::cast(object)->value();
return Script::cast(script)->column_offset();
}
const AccessorDescriptor Accessors::ScriptColumnOffset = {
ScriptGetColumnOffset,
IllegalSetter,
0
};
//
// Accessors::ScriptType
//
Object* Accessors::ScriptGetType(Object* object, void*) {
Object* script = JSValue::cast(object)->value();
return Script::cast(script)->type();
}
const AccessorDescriptor Accessors::ScriptType = {
ScriptGetType,
IllegalSetter,
0
};
//
// Accessors::FunctionPrototype
//
Object* Accessors::FunctionGetPrototype(Object* object, void*) {
bool found_it = false;
JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
if (!found_it) return Heap::undefined_value();
if (!function->has_prototype()) {
Object* prototype = Heap::AllocateFunctionPrototype(function);
if (prototype->IsFailure()) return prototype;
Object* result = function->SetPrototype(prototype);
if (result->IsFailure()) return result;
}
return function->prototype();
}
Object* Accessors::FunctionSetPrototype(JSObject* object,
Object* value,
void*) {
bool found_it = false;
JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
if (!found_it) return Heap::undefined_value();
if (function->has_initial_map()) {
// If the function has allocated the initial map
// replace it with a copy containing the new prototype.
Object* new_map = function->initial_map()->CopyDropTransitions();
if (new_map->IsFailure()) return new_map;
function->set_initial_map(Map::cast(new_map));
}
Object* prototype = function->SetPrototype(value);
if (prototype->IsFailure()) return prototype;
ASSERT(function->prototype() == value);
return function;
}
const AccessorDescriptor Accessors::FunctionPrototype = {
FunctionGetPrototype,
FunctionSetPrototype,
0
};
//
// Accessors::FunctionLength
//
Object* Accessors::FunctionGetLength(Object* object, void*) {
bool found_it = false;
JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
if (!found_it) return Smi::FromInt(0);
// Check if already compiled.
if (!function->is_compiled()) {
// If the function isn't compiled yet, the length is not computed
// correctly yet. Compile it now and return the right length.
HandleScope scope;
Handle<JSFunction> function_handle(function);
if (!CompileLazy(function_handle, KEEP_EXCEPTION)) {
return Failure::Exception();
}
return Smi::FromInt(function_handle->shared()->length());
} else {
return Smi::FromInt(function->shared()->length());
}
}
const AccessorDescriptor Accessors::FunctionLength = {
FunctionGetLength,
ReadOnlySetAccessor,
0
};
//
// Accessors::FunctionName
//
Object* Accessors::FunctionGetName(Object* object, void*) {
bool found_it = false;
JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
if (!found_it) return Heap::undefined_value();
return holder->shared()->name();
}
const AccessorDescriptor Accessors::FunctionName = {
FunctionGetName,
ReadOnlySetAccessor,
0
};
//
// Accessors::FunctionArguments
//
Object* Accessors::FunctionGetArguments(Object* object, void*) {
HandleScope scope;
bool found_it = false;
JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
if (!found_it) return Heap::undefined_value();
Handle<JSFunction> function(holder);
// Find the top invocation of the function by traversing frames.
for (JavaScriptFrameIterator it; !it.done(); it.Advance()) {
// Skip all frames that aren't invocations of the given function.
JavaScriptFrame* frame = it.frame();
if (frame->function() != *function) continue;
// If there is an arguments variable in the stack, we return that.
int index = ScopeInfo<>::StackSlotIndex(frame->FindCode(),
Heap::arguments_symbol());
if (index >= 0) return frame->GetExpression(index);
// If there isn't an arguments variable in the stack, we need to
// find the frame that holds the actual arguments passed to the
// function on the stack.
it.AdvanceToArgumentsFrame();
frame = it.frame();
// Get the number of arguments and construct an arguments object
// mirror for the right frame.
const int length = frame->GetProvidedParametersCount();
Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
Handle<FixedArray> array = Factory::NewFixedArray(length);
// Copy the parameters to the arguments object.
ASSERT(array->length() == length);
for (int i = 0; i < length; i++) array->set(i, frame->GetParameter(i));
arguments->set_elements(*array);
// Return the freshly allocated arguments object.
return *arguments;
}
// No frame corresponding to the given function found. Return null.
return Heap::null_value();
}
const AccessorDescriptor Accessors::FunctionArguments = {
FunctionGetArguments,
ReadOnlySetAccessor,
0
};
//
// Accessors::FunctionCaller
//
Object* Accessors::FunctionGetCaller(Object* object, void*) {
HandleScope scope;
bool found_it = false;
JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
if (!found_it) return Heap::undefined_value();
Handle<JSFunction> function(holder);
// Find the top invocation of the function by traversing frames.
for (JavaScriptFrameIterator it; !it.done(); it.Advance()) {
// Skip all frames that aren't invocations of the given function.
if (it.frame()->function() != *function) continue;
// Once we have found the frame, we need to go to the caller
// frame. This may require skipping through a number of top-level
// frames, e.g. frames for scripts not functions.
while (true) {
it.Advance();
if (it.done()) return Heap::null_value();
JSFunction* caller = JSFunction::cast(it.frame()->function());
if (!caller->shared()->is_toplevel()) return caller;
}
}
// No frame corresponding to the given function found. Return null.
return Heap::null_value();
}
const AccessorDescriptor Accessors::FunctionCaller = {
FunctionGetCaller,
ReadOnlySetAccessor,
0
};
//
// Accessors::ObjectPrototype
//
Object* Accessors::ObjectGetPrototype(Object* receiver, void*) {
Object* current = receiver->GetPrototype();
while (current->IsJSObject() &&
JSObject::cast(current)->map()->is_hidden_prototype()) {
current = current->GetPrototype();
}
return current;
}
Object* Accessors::ObjectSetPrototype(JSObject* receiver,
Object* value,
void*) {
// Before we can set the prototype we need to be sure
// prototype cycles are prevented.
// It is sufficient to validate that the receiver is not in the new prototype
// chain.
// Silently ignore the change if value is not a JSObject or null.
// SpiderMonkey behaves this way.
if (!value->IsJSObject() && !value->IsNull()) return value;
for (Object* pt = value; pt != Heap::null_value(); pt = pt->GetPrototype()) {
if (JSObject::cast(pt) == receiver) {
// Cycle detected.
HandleScope scope;
return Top::Throw(*Factory::NewError("cyclic_proto",
HandleVector<Object>(NULL, 0)));
}
}
// Find the first object in the chain whose prototype object is not
// hidden and set the new prototype on that object.
JSObject* current = receiver;
Object* current_proto = receiver->GetPrototype();
while (current_proto->IsJSObject() &&
JSObject::cast(current_proto)->map()->is_hidden_prototype()) {
current = JSObject::cast(current_proto);
current_proto = current_proto->GetPrototype();
}
// Set the new prototype of the object.
Object* new_map = current->map()->CopyDropTransitions();
if (new_map->IsFailure()) return new_map;
Map::cast(new_map)->set_prototype(value);
current->set_map(Map::cast(new_map));
// To be consistent with other Set functions, return the value.
return value;
}
const AccessorDescriptor Accessors::ObjectPrototype = {
ObjectGetPrototype,
ObjectSetPrototype,
0
};
} } // namespace v8::internal

View File

@ -1,97 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#ifndef V8_ACCESSORS_H_
#define V8_ACCESSORS_H_
namespace v8 { namespace internal {
// The list of accessor descriptors. This is a second-order macro
// taking a macro to be applied to all accessor descriptor names.
#define ACCESSOR_DESCRIPTOR_LIST(V) \
V(FunctionPrototype) \
V(FunctionLength) \
V(FunctionName) \
V(FunctionArguments) \
V(FunctionCaller) \
V(ArrayLength) \
V(StringLength) \
V(ScriptSource) \
V(ScriptName) \
V(ScriptLineOffset) \
V(ScriptColumnOffset) \
V(ScriptType) \
V(ObjectPrototype)
// Accessors contains all predefined proxy accessors.
class Accessors : public AllStatic {
public:
// Accessor descriptors.
#define ACCESSOR_DESCRIPTOR_DECLARATION(name) \
static const AccessorDescriptor name;
ACCESSOR_DESCRIPTOR_LIST(ACCESSOR_DESCRIPTOR_DECLARATION)
#undef ACCESSOR_DESCRIPTOR_DECLARATION
enum DescriptorId {
#define ACCESSOR_DESCRIPTOR_DECLARATION(name) \
k##name,
ACCESSOR_DESCRIPTOR_LIST(ACCESSOR_DESCRIPTOR_DECLARATION)
#undef ACCESSOR_DESCRIPTOR_DECLARATION
descriptorCount
};
// Accessor functions called directly from the runtime system.
static Object* FunctionGetPrototype(Object* object, void*);
static Object* FunctionSetPrototype(JSObject* object, Object* value, void*);
private:
// Accessor functions only used through the descriptor.
static Object* FunctionGetLength(Object* object, void*);
static Object* FunctionGetName(Object* object, void*);
static Object* FunctionGetArguments(Object* object, void*);
static Object* FunctionGetCaller(Object* object, void*);
static Object* ArraySetLength(JSObject* object, Object* value, void*);
static Object* ArrayGetLength(Object* object, void*);
static Object* StringGetLength(Object* object, void*);
static Object* ScriptGetName(Object* object, void*);
static Object* ScriptGetSource(Object* object, void*);
static Object* ScriptGetLineOffset(Object* object, void*);
static Object* ScriptGetColumnOffset(Object* object, void*);
static Object* ScriptGetType(Object* object, void*);
static Object* ObjectGetPrototype(Object* receiver, void*);
static Object* ObjectSetPrototype(JSObject* receiver, Object* value, void*);
// Helper functions.
static Object* FlattenNumber(Object* value);
static Object* IllegalSetter(JSObject*, Object*, void*);
static Object* IllegalGetAccessor(Object* object, void*);
static Object* ReadOnlySetAccessor(JSObject*, Object* value, void*);
};
} } // namespace v8::internal
#endif // V8_ACCESSORS_H_

View File

@ -1,187 +0,0 @@
// Copyright 2008 the V8 project 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.
#include <stdlib.h>
#include "v8.h"
namespace v8 { namespace internal {
void* Malloced::New(size_t size) {
ASSERT(NativeAllocationChecker::allocation_allowed());
void* result = malloc(size);
if (result == NULL) V8::FatalProcessOutOfMemory("Malloced operator new");
return result;
}
void Malloced::Delete(void* p) {
free(p);
}
void Malloced::FatalProcessOutOfMemory() {
V8::FatalProcessOutOfMemory("Out of memory");
}
#ifdef DEBUG
static void* invalid = static_cast<void*>(NULL);
void* Embedded::operator new(size_t size) {
UNREACHABLE();
return invalid;
}
void Embedded::operator delete(void* p) {
UNREACHABLE();
}
void* AllStatic::operator new(size_t size) {
UNREACHABLE();
return invalid;
}
void AllStatic::operator delete(void* p) {
UNREACHABLE();
}
#endif
char* StrDup(const char* str) {
int length = strlen(str);
char* result = NewArray<char>(length + 1);
memcpy(result, str, length * kCharSize);
result[length] = '\0';
return result;
}
int NativeAllocationChecker::allocation_disallowed_ = 0;
PreallocatedStorage PreallocatedStorage::in_use_list_(0);
PreallocatedStorage PreallocatedStorage::free_list_(0);
bool PreallocatedStorage::preallocated_ = false;
void PreallocatedStorage::Init(size_t size) {
ASSERT(free_list_.next_ == &free_list_);
ASSERT(free_list_.previous_ == &free_list_);
PreallocatedStorage* free_chunk =
reinterpret_cast<PreallocatedStorage*>(new char[size]);
free_list_.next_ = free_list_.previous_ = free_chunk;
free_chunk->next_ = free_chunk->previous_ = &free_list_;
free_chunk->size_ = size - sizeof(PreallocatedStorage);
preallocated_ = true;
}
void* PreallocatedStorage::New(size_t size) {
if (!preallocated_) {
return FreeStoreAllocationPolicy::New(size);
}
ASSERT(free_list_.next_ != &free_list_);
ASSERT(free_list_.previous_ != &free_list_);
size = (size + kPointerSize - 1) & ~(kPointerSize - 1);
// Search for exact fit.
for (PreallocatedStorage* storage = free_list_.next_;
storage != &free_list_;
storage = storage->next_) {
if (storage->size_ == size) {
storage->Unlink();
storage->LinkTo(&in_use_list_);
return reinterpret_cast<void*>(storage + 1);
}
}
// Search for first fit.
for (PreallocatedStorage* storage = free_list_.next_;
storage != &free_list_;
storage = storage->next_) {
if (storage->size_ >= size + sizeof(PreallocatedStorage)) {
storage->Unlink();
storage->LinkTo(&in_use_list_);
PreallocatedStorage* left_over =
reinterpret_cast<PreallocatedStorage*>(
reinterpret_cast<char*>(storage + 1) + size);
left_over->size_ = storage->size_ - size - sizeof(PreallocatedStorage);
ASSERT(size + left_over->size_ + sizeof(PreallocatedStorage) ==
storage->size_);
storage->size_ = size;
left_over->LinkTo(&free_list_);
return reinterpret_cast<void*>(storage + 1);
}
}
// Allocation failure.
ASSERT(false);
return NULL;
}
// We don't attempt to coalesce.
void PreallocatedStorage::Delete(void* p) {
if (p == NULL) {
return;
}
if (!preallocated_) {
FreeStoreAllocationPolicy::Delete(p);
return;
}
PreallocatedStorage* storage = reinterpret_cast<PreallocatedStorage*>(p) - 1;
ASSERT(storage->next_->previous_ == storage);
ASSERT(storage->previous_->next_ == storage);
storage->Unlink();
storage->LinkTo(&free_list_);
}
void PreallocatedStorage::LinkTo(PreallocatedStorage* other) {
next_ = other->next_;
other->next_->previous_ = this;
previous_ = other;
other->next_ = this;
}
void PreallocatedStorage::Unlink() {
next_->previous_ = previous_;
previous_->next_ = next_;
}
PreallocatedStorage::PreallocatedStorage(size_t size)
: size_(size) {
previous_ = next_ = this;
}
} } // namespace v8::internal

View File

@ -1,167 +0,0 @@
// Copyright 2008 the V8 project 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.
#ifndef V8_ALLOCATION_H_
#define V8_ALLOCATION_H_
namespace v8 { namespace internal {
// A class that controls whether allocation is allowed. This is for
// the C++ heap only!
class NativeAllocationChecker {
public:
typedef enum { ALLOW, DISALLOW } NativeAllocationAllowed;
explicit inline NativeAllocationChecker(NativeAllocationAllowed allowed)
: allowed_(allowed) {
#ifdef DEBUG
if (allowed == DISALLOW) {
allocation_disallowed_++;
}
#endif
}
~NativeAllocationChecker() {
#ifdef DEBUG
if (allowed_ == DISALLOW) {
allocation_disallowed_--;
}
#endif
ASSERT(allocation_disallowed_ >= 0);
}
static inline bool allocation_allowed() {
return allocation_disallowed_ == 0;
}
private:
// This static counter ensures that NativeAllocationCheckers can be nested.
static int allocation_disallowed_;
// This flag applies to this particular instance.
NativeAllocationAllowed allowed_;
};
// Superclass for classes managed with new & delete.
class Malloced {
public:
void* operator new(size_t size) { return New(size); }
void operator delete(void* p) { Delete(p); }
static void FatalProcessOutOfMemory();
static void* New(size_t size);
static void Delete(void* p);
};
// A macro is used for defining the base class used for embedded instances.
// The reason is some compilers allocate a minimum of one word for the
// superclass. The macro prevents the use of new & delete in debug mode.
// In release mode we are not willing to pay this overhead.
#ifdef DEBUG
// Superclass for classes with instances allocated inside stack
// activations or inside other objects.
class Embedded {
public:
void* operator new(size_t size);
void operator delete(void* p);
};
#define BASE_EMBEDDED : public Embedded
#else
#define BASE_EMBEDDED
#endif
// Superclass for classes only using statics.
class AllStatic {
#ifdef DEBUG
public:
void* operator new(size_t size);
void operator delete(void* p);
#endif
};
template <typename T>
static T* NewArray(int size) {
ASSERT(NativeAllocationChecker::allocation_allowed());
T* result = new T[size];
if (result == NULL) Malloced::FatalProcessOutOfMemory();
return result;
}
template <typename T>
static void DeleteArray(T* array) {
delete[] array;
}
// The normal strdup function uses malloc. This version of StrDup
// uses new and calls the FatalProcessOutOfMemory handler if
// allocation fails.
char* StrDup(const char* str);
// Allocation policy for allocating in the C free store using malloc
// and free. Used as the default policy for lists.
class FreeStoreAllocationPolicy {
public:
INLINE(static void* New(size_t size)) { return Malloced::New(size); }
INLINE(static void Delete(void* p)) { Malloced::Delete(p); }
};
// Allocation policy for allocating in preallocated space.
// Used as an allocation policy for ScopeInfo when generating
// stack traces.
class PreallocatedStorage : public AllStatic {
public:
explicit PreallocatedStorage(size_t size);
size_t size() { return size_; }
static void* New(size_t size);
static void Delete(void* p);
// Preallocate a set number of bytes.
static void Init(size_t size);
private:
size_t size_;
PreallocatedStorage* previous_;
PreallocatedStorage* next_;
static bool preallocated_;
static PreallocatedStorage in_use_list_;
static PreallocatedStorage free_list_;
void LinkTo(PreallocatedStorage* other);
void Unlink();
DISALLOW_IMPLICIT_CONSTRUCTORS(PreallocatedStorage);
};
} } // namespace v8::internal
#endif // V8_ALLOCATION_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,490 +0,0 @@
// Copyright 2008 the V8 project 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.
#ifndef V8_API_H_
#define V8_API_H_
#include "factory.h"
namespace v8 {
// Constants used in the implementation of the API. The most natural thing
// would usually be to place these with the classes that use them, but
// we want to keep them out of v8.h because it is an externally
// visible file.
class Consts {
public:
enum TemplateType {
FUNCTION_TEMPLATE = 0,
OBJECT_TEMPLATE = 1
};
};
// Utilities for working with neander-objects, primitive
// env-independent JSObjects used by the api.
class NeanderObject {
public:
explicit NeanderObject(int size);
inline NeanderObject(v8::internal::Handle<v8::internal::Object> obj);
inline NeanderObject(v8::internal::Object* obj);
inline v8::internal::Object* get(int index);
inline void set(int index, v8::internal::Object* value);
inline v8::internal::Handle<v8::internal::JSObject> value() { return value_; }
int size();
private:
v8::internal::Handle<v8::internal::JSObject> value_;
};
// Utilities for working with neander-arrays, a simple extensible
// array abstraction built on neander-objects.
class NeanderArray {
public:
NeanderArray();
inline NeanderArray(v8::internal::Handle<v8::internal::Object> obj);
inline v8::internal::Handle<v8::internal::JSObject> value() {
return obj_.value();
}
void add(v8::internal::Handle<v8::internal::Object> value);
int length();
v8::internal::Object* get(int index);
// Change the value at an index to undefined value. If the index is
// out of bounds, the request is ignored. Returns the old value.
void set(int index, v8::internal::Object* value);
private:
NeanderObject obj_;
};
NeanderObject::NeanderObject(v8::internal::Handle<v8::internal::Object> obj)
: value_(v8::internal::Handle<v8::internal::JSObject>::cast(obj)) { }
NeanderObject::NeanderObject(v8::internal::Object* obj)
: value_(v8::internal::Handle<v8::internal::JSObject>(
v8::internal::JSObject::cast(obj))) { }
NeanderArray::NeanderArray(v8::internal::Handle<v8::internal::Object> obj)
: obj_(obj) { }
v8::internal::Object* NeanderObject::get(int offset) {
ASSERT(value()->HasFastElements());
return v8::internal::FixedArray::cast(value()->elements())->get(offset);
}
void NeanderObject::set(int offset, v8::internal::Object* value) {
ASSERT(value_->HasFastElements());
v8::internal::FixedArray::cast(value_->elements())->set(offset, value);
}
template <typename T> static inline T ToCData(v8::internal::Object* obj) {
STATIC_ASSERT(sizeof(T) == sizeof(v8::internal::Address));
return reinterpret_cast<T>(
reinterpret_cast<intptr_t>(v8::internal::Proxy::cast(obj)->proxy()));
}
template <typename T>
static inline v8::internal::Handle<v8::internal::Object> FromCData(T obj) {
STATIC_ASSERT(sizeof(T) == sizeof(v8::internal::Address));
return v8::internal::Factory::NewProxy(
reinterpret_cast<v8::internal::Address>(reinterpret_cast<intptr_t>(obj)));
}
v8::Arguments::Arguments(v8::Local<v8::Value> data,
v8::Local<v8::Object> holder,
v8::Local<v8::Function> callee,
bool is_construct_call,
void** values, int length)
: data_(data), holder_(holder), callee_(callee),
is_construct_call_(is_construct_call),
values_(values), length_(length) { }
enum ExtensionTraversalState {
UNVISITED, VISITED, INSTALLED
};
class RegisteredExtension {
public:
explicit RegisteredExtension(Extension* extension);
static void Register(RegisteredExtension* that);
Extension* extension() { return extension_; }
RegisteredExtension* next() { return next_; }
RegisteredExtension* next_auto() { return next_auto_; }
ExtensionTraversalState state() { return state_; }
void set_state(ExtensionTraversalState value) { state_ = value; }
static RegisteredExtension* first_extension() { return first_extension_; }
private:
Extension* extension_;
RegisteredExtension* next_;
RegisteredExtension* next_auto_;
ExtensionTraversalState state_;
static RegisteredExtension* first_extension_;
static RegisteredExtension* first_auto_extension_;
};
class ImplementationUtilities {
public:
static v8::Handle<v8::Primitive> Undefined();
static v8::Handle<v8::Primitive> Null();
static v8::Handle<v8::Boolean> True();
static v8::Handle<v8::Boolean> False();
static int GetNameCount(ExtensionConfiguration* that) {
return that->name_count_;
}
static const char** GetNames(ExtensionConfiguration* that) {
return that->names_;
}
static v8::Arguments NewArguments(Local<Value> data,
Local<Object> holder,
Local<Function> callee,
bool is_construct_call,
void** argv, int argc) {
return v8::Arguments(data, holder, callee, is_construct_call, argv, argc);
}
// Introduce an alias for the handle scope data to allow non-friends
// to access the HandleScope data.
typedef v8::HandleScope::Data HandleScopeData;
static HandleScopeData* CurrentHandleScope() {
return &v8::HandleScope::current_;
}
#ifdef DEBUG
static void ZapHandleRange(void** begin, void** end) {
v8::HandleScope::ZapRange(begin, end);
}
#endif
};
class Utils {
public:
static bool ReportApiFailure(const char* location, const char* message);
static Local<FunctionTemplate> ToFunctionTemplate(NeanderObject obj);
static Local<ObjectTemplate> ToObjectTemplate(NeanderObject obj);
static inline Local<Context> ToLocal(
v8::internal::Handle<v8::internal::Context> obj);
static inline Local<Value> ToLocal(
v8::internal::Handle<v8::internal::Object> obj);
static inline Local<Function> ToLocal(
v8::internal::Handle<v8::internal::JSFunction> obj);
static inline Local<String> ToLocal(
v8::internal::Handle<v8::internal::String> obj);
static inline Local<Object> ToLocal(
v8::internal::Handle<v8::internal::JSObject> obj);
static inline Local<Array> ToLocal(
v8::internal::Handle<v8::internal::JSArray> obj);
static inline Local<External> ToLocal(
v8::internal::Handle<v8::internal::Proxy> obj);
static inline Local<Message> MessageToLocal(
v8::internal::Handle<v8::internal::Object> obj);
static inline Local<Number> NumberToLocal(
v8::internal::Handle<v8::internal::Object> obj);
static inline Local<Integer> IntegerToLocal(
v8::internal::Handle<v8::internal::Object> obj);
static inline Local<Uint32> Uint32ToLocal(
v8::internal::Handle<v8::internal::Object> obj);
static inline Local<FunctionTemplate> ToLocal(
v8::internal::Handle<v8::internal::FunctionTemplateInfo> obj);
static inline Local<ObjectTemplate> ToLocal(
v8::internal::Handle<v8::internal::ObjectTemplateInfo> obj);
static inline Local<Signature> ToLocal(
v8::internal::Handle<v8::internal::SignatureInfo> obj);
static inline Local<TypeSwitch> ToLocal(
v8::internal::Handle<v8::internal::TypeSwitchInfo> obj);
static inline v8::internal::Handle<v8::internal::TemplateInfo>
OpenHandle(Template* that);
static inline v8::internal::Handle<v8::internal::FunctionTemplateInfo>
OpenHandle(FunctionTemplate* that);
static inline v8::internal::Handle<v8::internal::ObjectTemplateInfo>
OpenHandle(ObjectTemplate* that);
static inline v8::internal::Handle<v8::internal::Object>
OpenHandle(Data* data);
static inline v8::internal::Handle<v8::internal::JSObject>
OpenHandle(v8::Object* data);
static inline v8::internal::Handle<v8::internal::JSArray>
OpenHandle(v8::Array* data);
static inline v8::internal::Handle<v8::internal::String>
OpenHandle(String* data);
static inline v8::internal::Handle<v8::internal::JSFunction>
OpenHandle(Script* data);
static inline v8::internal::Handle<v8::internal::JSFunction>
OpenHandle(Function* data);
static inline v8::internal::Handle<v8::internal::JSObject>
OpenHandle(Message* message);
static inline v8::internal::Handle<v8::internal::Context>
OpenHandle(v8::Context* context);
static inline v8::internal::Handle<v8::internal::SignatureInfo>
OpenHandle(v8::Signature* sig);
static inline v8::internal::Handle<v8::internal::TypeSwitchInfo>
OpenHandle(v8::TypeSwitch* that);
static inline v8::internal::Handle<v8::internal::Proxy>
OpenHandle(v8::External* that);
};
template <class T>
static inline T* ToApi(v8::internal::Handle<v8::internal::Object> obj) {
return reinterpret_cast<T*>(obj.location());
}
template <class T>
v8::internal::Handle<T> v8::internal::Handle<T>::EscapeFrom(
HandleScope* scope) {
return Utils::OpenHandle(*scope->Close(Utils::ToLocal(*this)));
}
// Implementations of ToLocal
#define MAKE_TO_LOCAL(Name, From, To) \
Local<v8::To> Utils::Name(v8::internal::Handle<v8::internal::From> obj) { \
return Local<To>(reinterpret_cast<To*>(obj.location())); \
}
MAKE_TO_LOCAL(ToLocal, Context, Context)
MAKE_TO_LOCAL(ToLocal, Object, Value)
MAKE_TO_LOCAL(ToLocal, JSFunction, Function)
MAKE_TO_LOCAL(ToLocal, String, String)
MAKE_TO_LOCAL(ToLocal, JSObject, Object)
MAKE_TO_LOCAL(ToLocal, JSArray, Array)
MAKE_TO_LOCAL(ToLocal, Proxy, External)
MAKE_TO_LOCAL(ToLocal, FunctionTemplateInfo, FunctionTemplate)
MAKE_TO_LOCAL(ToLocal, ObjectTemplateInfo, ObjectTemplate)
MAKE_TO_LOCAL(ToLocal, SignatureInfo, Signature)
MAKE_TO_LOCAL(ToLocal, TypeSwitchInfo, TypeSwitch)
MAKE_TO_LOCAL(MessageToLocal, Object, Message)
MAKE_TO_LOCAL(NumberToLocal, Object, Number)
MAKE_TO_LOCAL(IntegerToLocal, Object, Integer)
MAKE_TO_LOCAL(Uint32ToLocal, Object, Uint32)
#undef MAKE_TO_LOCAL
// Implementations of OpenHandle
#define MAKE_OPEN_HANDLE(From, To) \
v8::internal::Handle<v8::internal::To> Utils::OpenHandle(v8::From* that) { \
return v8::internal::Handle<v8::internal::To>( \
reinterpret_cast<v8::internal::To**>(that)); \
}
MAKE_OPEN_HANDLE(Template, TemplateInfo)
MAKE_OPEN_HANDLE(FunctionTemplate, FunctionTemplateInfo)
MAKE_OPEN_HANDLE(ObjectTemplate, ObjectTemplateInfo)
MAKE_OPEN_HANDLE(Signature, SignatureInfo)
MAKE_OPEN_HANDLE(TypeSwitch, TypeSwitchInfo)
MAKE_OPEN_HANDLE(Data, Object)
MAKE_OPEN_HANDLE(Object, JSObject)
MAKE_OPEN_HANDLE(Array, JSArray)
MAKE_OPEN_HANDLE(String, String)
MAKE_OPEN_HANDLE(Script, JSFunction)
MAKE_OPEN_HANDLE(Function, JSFunction)
MAKE_OPEN_HANDLE(Message, JSObject)
MAKE_OPEN_HANDLE(Context, Context)
MAKE_OPEN_HANDLE(External, Proxy)
#undef MAKE_OPEN_HANDLE
namespace internal {
// This class is here in order to be able to declare it a friend of
// HandleScope. Moving these methods to be members of HandleScope would be
// neat in some ways, but it would expose external implementation details in
// our public header file, which is undesirable.
//
// There is a singleton instance of this class to hold the per-thread data.
// For multithreaded V8 programs this data is copied in and out of storage
// so that the currently executing thread always has its own copy of this
// data.
class HandleScopeImplementer {
public:
HandleScopeImplementer()
: blocks(0),
entered_contexts_(0),
saved_contexts_(0) {
Initialize();
}
void Initialize() {
blocks.Initialize(0);
entered_contexts_.Initialize(0);
saved_contexts_.Initialize(0);
spare = NULL;
ignore_out_of_memory = false;
call_depth = 0;
}
static HandleScopeImplementer* instance();
// Threading support for handle data.
static int ArchiveSpacePerThread();
static char* RestoreThread(char* from);
static char* ArchiveThread(char* to);
// Garbage collection support.
static void Iterate(v8::internal::ObjectVisitor* v);
static char* Iterate(v8::internal::ObjectVisitor* v, char* data);
inline void** GetSpareOrNewBlock();
inline void DeleteExtensions(int extensions);
inline void IncrementCallDepth() {call_depth++;}
inline void DecrementCallDepth() {call_depth--;}
inline bool CallDepthIsZero() { return call_depth == 0; }
inline void EnterContext(Handle<Object> context);
inline bool LeaveLastContext();
// Returns the last entered context or an empty handle if no
// contexts have been entered.
inline Handle<Object> LastEnteredContext();
inline void SaveContext(Handle<Object> context);
inline Handle<Object> RestoreContext();
inline bool HasSavedContexts();
inline List<void**>* Blocks() { return &blocks; }
inline bool IgnoreOutOfMemory() { return ignore_out_of_memory; }
inline void SetIgnoreOutOfMemory(bool value) { ignore_out_of_memory = value; }
private:
List<void**> blocks;
Object** spare;
int call_depth;
// Used as a stack to keep track of entered contexts.
List<Handle<Object> > entered_contexts_;
// Used as a stack to keep track of saved contexts.
List<Handle<Object> > saved_contexts_;
bool ignore_out_of_memory;
// This is only used for threading support.
ImplementationUtilities::HandleScopeData handle_scope_data_;
static void Iterate(ObjectVisitor* v,
List<void**>* blocks,
ImplementationUtilities::HandleScopeData* handle_data);
char* RestoreThreadHelper(char* from);
char* ArchiveThreadHelper(char* to);
DISALLOW_COPY_AND_ASSIGN(HandleScopeImplementer);
};
static const int kHandleBlockSize = v8::internal::KB - 2; // fit in one page
void HandleScopeImplementer::SaveContext(Handle<Object> context) {
saved_contexts_.Add(context);
}
Handle<Object> HandleScopeImplementer::RestoreContext() {
return saved_contexts_.RemoveLast();
}
bool HandleScopeImplementer::HasSavedContexts() {
return !saved_contexts_.is_empty();
}
void HandleScopeImplementer::EnterContext(Handle<Object> context) {
entered_contexts_.Add(context);
}
bool HandleScopeImplementer::LeaveLastContext() {
if (entered_contexts_.is_empty()) return false;
entered_contexts_.RemoveLast();
return true;
}
Handle<Object> HandleScopeImplementer::LastEnteredContext() {
if (entered_contexts_.is_empty()) return Handle<Object>::null();
return entered_contexts_.last();
}
// If there's a spare block, use it for growing the current scope.
void** HandleScopeImplementer::GetSpareOrNewBlock() {
void** block = (spare != NULL) ?
reinterpret_cast<void**>(spare) :
NewArray<void*>(kHandleBlockSize);
spare = NULL;
return block;
}
void HandleScopeImplementer::DeleteExtensions(int extensions) {
if (spare != NULL) {
DeleteArray(spare);
spare = NULL;
}
for (int i = extensions; i > 1; --i) {
void** block = blocks.RemoveLast();
#ifdef DEBUG
ImplementationUtilities::ZapHandleRange(block, &block[kHandleBlockSize]);
#endif
DeleteArray(block);
}
spare = reinterpret_cast<Object**>(blocks.RemoveLast());
#ifdef DEBUG
ImplementationUtilities::ZapHandleRange(
reinterpret_cast<void**>(spare),
reinterpret_cast<void**>(&spare[kHandleBlockSize]));
#endif
}
} } // namespace v8::internal
#endif // V8_API_H_

View File

@ -1,93 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
// This file contains infrastructure used by the API. See
// v8natives.js for an explanation of these files are processed and
// loaded.
function CreateDate(time) {
var date = new ORIGINAL_DATE();
date.setTime(time);
return date;
}
const kApiFunctionCache = {};
const functionCache = kApiFunctionCache;
function Instantiate(data, name) {
if (!%IsTemplate(data)) return data;
var tag = %GetTemplateField(data, kApiTagOffset);
switch (tag) {
case kFunctionTag:
return InstantiateFunction(data, name);
case kNewObjectTag:
var Constructor = %GetTemplateField(data, kApiConstructorOffset);
var result = Constructor ? new (Instantiate(Constructor))() : {};
ConfigureTemplateInstance(result, data);
return result;
default:
throw 'Unknown API tag <' + tag + '>';
}
}
function InstantiateFunction(data, name) {
var serialNumber = %GetTemplateField(data, kApiSerialNumberOffset);
if (!(serialNumber in kApiFunctionCache)) {
kApiFunctionCache[serialNumber] = null;
var fun = %CreateApiFunction(data);
if (name) %FunctionSetName(fun, name);
kApiFunctionCache[serialNumber] = fun;
var prototype = %GetTemplateField(data, kApiPrototypeTemplateOffset);
fun.prototype = prototype ? Instantiate(prototype) : {};
%SetProperty(fun.prototype, "constructor", fun, DONT_ENUM);
var parent = %GetTemplateField(data, kApiParentTemplateOffset);
if (parent) {
var parent_fun = Instantiate(parent);
fun.prototype.__proto__ = parent_fun.prototype;
}
ConfigureTemplateInstance(fun, data);
}
return kApiFunctionCache[serialNumber];
}
function ConfigureTemplateInstance(obj, data) {
var properties = %GetTemplateField(data, kApiPropertyListOffset);
if (properties) {
for (var i = 0; i < properties[0]; i += 3) {
var name = properties[i + 1];
var prop_data = properties[i + 2];
var attributes = properties[i + 3];
var value = Instantiate(prop_data, name);
%SetProperty(obj, name, value, attributes);
}
}
}

View File

@ -1,70 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#ifndef V8_ARGUMENTS_H_
#define V8_ARGUMENTS_H_
namespace v8 { namespace internal {
// Arguments provides access to runtime call parameters.
//
// It uses the fact that the instance fields of Arguments
// (length_, arguments_) are "overlayed" with the parameters
// (no. of parameters, and the parameter pointer) passed so
// that inside the C++ function, the parameters passed can
// be accessed conveniently:
//
// Object* Runtime_function(Arguments args) {
// ... use args[i] here ...
// }
class Arguments BASE_EMBEDDED {
public:
Object*& operator[] (int index) {
ASSERT(0 <= index && index < length_);
return arguments_[-index];
}
template <class S> Handle<S> at(int index) {
Object** value = &((*this)[index]);
// This cast checks that the object we're accessing does indeed have the
// expected type.
S::cast(*value);
return Handle<S>(reinterpret_cast<S**>(value));
}
// Get the total number of arguments including the receiver.
int length() const { return length_; }
private:
int length_;
Object** arguments_;
};
} } // namespace v8::internal
#endif // V8_ARGUMENTS_H_

View File

@ -1,959 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
// This file relies on the fact that the following declarations have been made
// in runtime.js:
// const $Array = global.Array;
// -------------------------------------------------------------------
// Global list of arrays visited during toString, toLocaleString and
// join invocations.
var visited_arrays = new $Array();
// Gets a sorted array of array keys. Useful for operations on sparse
// arrays. Dupes have not been removed.
function GetSortedArrayKeys(array, intervals) {
var length = intervals.length;
var keys = [];
for (var k = 0; k < length; k++) {
var key = intervals[k];
if (key < 0) {
var j = -1 - key;
var limit = j + intervals[++k];
for (; j < limit; j++) {
var e = array[j];
if (!IS_UNDEFINED(e) || j in array) {
keys.push(j);
}
}
} else {
// The case where key is undefined also ends here.
if (!IS_UNDEFINED(key)) {
var e = array[key];
if (!IS_UNDEFINED(e) || key in array) {
keys.push(key);
}
}
}
}
keys.sort(function(a, b) { return a - b; });
return keys;
}
// Optimized for sparse arrays if separator is ''.
function SparseJoin(array, len, convert) {
var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len));
var builder = new StringBuilder();
var last_key = -1;
var keys_length = keys.length;
for (var i = 0; i < keys_length; i++) {
var key = keys[i];
if (key != last_key) {
var e = array[key];
builder.add(convert(e));
last_key = key;
}
}
return builder.generate();
}
function UseSparseVariant(object, length, is_array) {
return is_array &&
length > 1000 &&
(!%_IsSmi(length) ||
%EstimateNumberOfElements(object) < (length >> 2));
}
function Join(array, length, separator, convert) {
if (length == 0) return '';
var is_array = IS_ARRAY(array);
if (is_array) {
// If the array is cyclic, return the empty string for already
// visited arrays.
if (!%PushIfAbsent(visited_arrays, array)) return '';
}
// Attempt to convert the elements.
try {
if (UseSparseVariant(array, length, is_array) && separator === '') {
return SparseJoin(array, length, convert);
}
// Fast case for one-element arrays.
if (length == 1) {
var e = array[0];
if (!IS_UNDEFINED(e) || (0 in array)) {
return convert(e);
}
}
var builder = new StringBuilder();
for (var i = 0; i < length; i++) {
var e = array[i];
if (i != 0) builder.add(separator);
if (!IS_UNDEFINED(e) || (i in array)) {
builder.add(convert(e));
}
}
return builder.generate();
} finally {
// Make sure to pop the visited array no matter what happens.
if (is_array) visited_arrays.pop();
}
}
function ConvertToString(e) {
if (e == null) return '';
else return ToString(e);
}
function ConvertToLocaleString(e) {
if (e == null) return '';
else {
// e_obj's toLocaleString might be overwritten, check if it is a function.
// Call ToString if toLocaleString is not a function.
// See issue 877615.
var e_obj = ToObject(e);
if (IS_FUNCTION(e_obj.toLocaleString))
return e_obj.toLocaleString();
else
return ToString(e);
}
}
// This function implements the optimized splice implementation that can use
// special array operations to handle sparse arrays in a sensible fashion.
function SmartSlice(array, start_i, del_count, len, deleted_elements) {
// Move deleted elements to a new array (the return value from splice).
// Intervals array can contain keys and intervals. See comment in Concat.
var intervals = %GetArrayKeys(array, start_i + del_count);
var length = intervals.length;
for (var k = 0; k < length; k++) {
var key = intervals[k];
if (key < 0) {
var j = -1 - key;
var interval_limit = j + intervals[++k];
if (j < start_i) {
j = start_i;
}
for (; j < interval_limit; j++) {
// ECMA-262 15.4.4.12 line 10. The spec could also be
// interpreted such that %HasLocalProperty would be the
// appropriate test. We follow KJS in consulting the
// prototype.
var current = array[j];
if (!IS_UNDEFINED(current) || j in array) {
deleted_elements[j - start_i] = current;
}
}
} else {
if (!IS_UNDEFINED(key)) {
if (key >= start_i) {
// ECMA-262 15.4.4.12 line 10. The spec could also be
// interpreted such that %HasLocalProperty would be the
// appropriate test. We follow KJS in consulting the
// prototype.
var current = array[key];
if (!IS_UNDEFINED(current) || key in array) {
deleted_elements[key - start_i] = current;
}
}
}
}
}
}
// This function implements the optimized splice implementation that can use
// special array operations to handle sparse arrays in a sensible fashion.
function SmartMove(array, start_i, del_count, len, num_additional_args) {
// Move data to new array.
var new_array = new $Array(len - del_count + num_additional_args);
var intervals = %GetArrayKeys(array, len);
var length = intervals.length;
for (var k = 0; k < length; k++) {
var key = intervals[k];
if (key < 0) {
var j = -1 - key;
var interval_limit = j + intervals[++k];
while (j < start_i && j < interval_limit) {
// The spec could also be interpreted such that
// %HasLocalProperty would be the appropriate test. We follow
// KJS in consulting the prototype.
var current = array[j];
if (!IS_UNDEFINED(current) || j in array) {
new_array[j] = current;
}
j++;
}
j = start_i + del_count;
while (j < interval_limit) {
// ECMA-262 15.4.4.12 lines 24 and 41. The spec could also be
// interpreted such that %HasLocalProperty would be the
// appropriate test. We follow KJS in consulting the
// prototype.
var current = array[j];
if (!IS_UNDEFINED(current) || j in array) {
new_array[j - del_count + num_additional_args] = current;
}
j++;
}
} else {
if (!IS_UNDEFINED(key)) {
if (key < start_i) {
// The spec could also be interpreted such that
// %HasLocalProperty would be the appropriate test. We follow
// KJS in consulting the prototype.
var current = array[key];
if (!IS_UNDEFINED(current) || key in array) {
new_array[key] = current;
}
} else if (key >= start_i + del_count) {
// ECMA-262 15.4.4.12 lines 24 and 41. The spec could also
// be interpreted such that %HasLocalProperty would be the
// appropriate test. We follow KJS in consulting the
// prototype.
var current = array[key];
if (!IS_UNDEFINED(current) || key in array) {
new_array[key - del_count + num_additional_args] = current;
}
}
}
}
}
// Move contents of new_array into this array
%MoveArrayContents(new_array, array);
}
// This is part of the old simple-minded splice. We are using it either
// because the receiver is not an array (so we have no choice) or because we
// know we are not deleting or moving a lot of elements.
function SimpleSlice(array, start_i, del_count, len, deleted_elements) {
for (var i = 0; i < del_count; i++) {
var index = start_i + i;
// The spec could also be interpreted such that %HasLocalProperty
// would be the appropriate test. We follow KJS in consulting the
// prototype.
var current = array[index];
if (!IS_UNDEFINED(current) || index in array)
deleted_elements[i] = current;
}
}
function SimpleMove(array, start_i, del_count, len, num_additional_args) {
if (num_additional_args !== del_count) {
// Move the existing elements after the elements to be deleted
// to the right position in the resulting array.
if (num_additional_args > del_count) {
for (var i = len - del_count; i > start_i; i--) {
var from_index = i + del_count - 1;
var to_index = i + num_additional_args - 1;
// The spec could also be interpreted such that
// %HasLocalProperty would be the appropriate test. We follow
// KJS in consulting the prototype.
var current = array[from_index];
if (!IS_UNDEFINED(current) || from_index in array) {
array[to_index] = current;
} else {
delete array[to_index];
}
}
} else {
for (var i = start_i; i < len - del_count; i++) {
var from_index = i + del_count;
var to_index = i + num_additional_args;
// The spec could also be interpreted such that
// %HasLocalProperty would be the appropriate test. We follow
// KJS in consulting the prototype.
var current = array[from_index];
if (!IS_UNDEFINED(current) || from_index in array) {
array[to_index] = current;
} else {
delete array[to_index];
}
}
for (var i = len; i > len - del_count + num_additional_args; i--) {
delete array[i - 1];
}
}
}
}
// -------------------------------------------------------------------
function ArrayToString() {
if (!IS_ARRAY(this)) {
throw new $TypeError('Array.prototype.toString is not generic');
}
return Join(this, this.length, ',', ConvertToString);
}
function ArrayToLocaleString() {
if (!IS_ARRAY(this)) {
throw new $TypeError('Array.prototype.toString is not generic');
}
return Join(this, this.length, ',', ConvertToLocaleString);
}
function ArrayJoin(separator) {
if (IS_UNDEFINED(separator)) separator = ',';
else separator = ToString(separator);
return Join(this, ToUint32(this.length), separator, ConvertToString);
}
// Removes the last element from the array and returns it. See
// ECMA-262, section 15.4.4.6.
function ArrayPop() {
var n = ToUint32(this.length);
if (n == 0) {
this.length = n;
return;
}
n--;
var value = this[n];
this.length = n;
delete this[n];
return value;
}
// Appends the arguments to the end of the array and returns the new
// length of the array. See ECMA-262, section 15.4.4.7.
function ArrayPush() {
var n = ToUint32(this.length);
var m = %_ArgumentsLength();
for (var i = 0; i < m; i++) {
this[i+n] = %_Arguments(i);
}
this.length = n + m;
return this.length;
}
function ArrayConcat(arg1) { // length == 1
var arg_number = 0, arg_count = %_ArgumentsLength();
var n = 0;
var A = $Array(1 + arg_count);
var E = this;
while (true) {
if (IS_ARRAY(E)) {
// This is an array of intervals or an array of keys. Keys are
// represented by non-negative integers. Intervals are represented by
// negative integers, followed by positive counts. The interval start
// is determined by subtracting the entry from -1. There may also be
// undefined entries in the array which should be skipped.
var intervals = %GetArrayKeys(E, E.length);
var length = intervals.length;
for (var k = 0; k < length; k++) {
var key = intervals[k];
if (key < 0) {
var j = -1 - key;
var limit = j + intervals[++k];
for (; j < limit; j++) {
if (j in E) {
A[n + j] = E[j];
}
}
} else {
// The case where key is undefined also ends here.
if (!IS_UNDEFINED(key)) {
A[n + key] = E[key];
}
}
}
n += E.length;
} else {
A[n++] = E;
}
if (arg_number == arg_count) break;
E = %_Arguments(arg_number++);
}
A.length = n; // may contain empty arrays
return A;
}
// For implementing reverse() on large, sparse arrays.
function SparseReverse(array, len) {
var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len));
var high_counter = keys.length - 1;
var low_counter = 0;
while (low_counter <= high_counter) {
var i = keys[low_counter];
var j = keys[high_counter];
var j_complement = len - j - 1;
var low, high;
if (j_complement <= i) {
high = j;
while (keys[--high_counter] == j);
low = j_complement;
}
if (j_complement >= i) {
low = i;
while (keys[++low_counter] == i);
high = len - i - 1;
}
var current_i = array[low];
if (!IS_UNDEFINED(current_i) || low in array) {
var current_j = array[high];
if (!IS_UNDEFINED(current_j) || high in array) {
array[low] = current_j;
array[high] = current_i;
} else {
array[high] = current_i;
delete array[low];
}
} else {
var current_j = array[high];
if (!IS_UNDEFINED(current_j) || high in array) {
array[low] = current_j;
delete array[high];
}
}
}
}
function ArrayReverse() {
var j = ToUint32(this.length) - 1;
if (UseSparseVariant(this, j, IS_ARRAY(this))) {
SparseReverse(this, j+1);
return this;
}
for (var i = 0; i < j; i++, j--) {
var current_i = this[i];
if (!IS_UNDEFINED(current_i) || i in this) {
var current_j = this[j];
if (!IS_UNDEFINED(current_j) || j in this) {
this[i] = current_j;
this[j] = current_i;
} else {
this[j] = current_i;
delete this[i];
}
} else {
var current_j = this[j];
if (!IS_UNDEFINED(current_j) || j in this) {
this[i] = current_j;
delete this[j];
}
}
}
return this;
}
function ArrayShift() {
var len = ToUint32(this.length);
if (len === 0) {
this.length = 0;
return;
}
var first = this[0];
if (IS_ARRAY(this))
SmartMove(this, 0, 1, len, 0);
else
SimpleMove(this, 0, 1, len, 0);
this.length = len - 1;
return first;
}
function ArrayUnshift(arg1) { // length == 1
var len = ToUint32(this.length);
var num_arguments = %_ArgumentsLength();
if (IS_ARRAY(this))
SmartMove(this, 0, 0, len, num_arguments);
else
SimpleMove(this, 0, 0, len, num_arguments);
for (var i = 0; i < num_arguments; i++) {
this[i] = %_Arguments(i);
}
this.length = len + num_arguments;
return len + num_arguments;
}
function ArraySlice(start, end) {
var len = ToUint32(this.length);
var start_i = TO_INTEGER(start);
var end_i = len;
if (end !== void 0) end_i = TO_INTEGER(end);
if (start_i < 0) {
start_i += len;
if (start_i < 0) start_i = 0;
} else {
if (start_i > len) start_i = len;
}
if (end_i < 0) {
end_i += len;
if (end_i < 0) end_i = 0;
} else {
if (end_i > len) end_i = len;
}
var result = [];
if (end_i < start_i) return result;
if (IS_ARRAY(this)) {
SmartSlice(this, start_i, end_i - start_i, len, result);
} else {
SimpleSlice(this, start_i, end_i - start_i, len, result);
}
result.length = end_i - start_i;
return result;
}
function ArraySplice(start, delete_count) {
var num_arguments = %_ArgumentsLength();
// SpiderMonkey and KJS return undefined in the case where no
// arguments are given instead of using the implicit undefined
// arguments. This does not follow ECMA-262, but we do the same for
// compatibility.
if (num_arguments == 0) return;
var len = ToUint32(this.length);
var start_i = TO_INTEGER(start);
if (start_i < 0) {
start_i += len;
if (start_i < 0) start_i = 0;
} else {
if (start_i > len) start_i = len;
}
// SpiderMonkey and KJS treat the case where no delete count is
// given differently from when an undefined delete count is given.
// This does not follow ECMA-262, but we do the same for
// compatibility.
var del_count = 0;
if (num_arguments > 1) {
del_count = TO_INTEGER(delete_count);
if (del_count < 0) del_count = 0;
if (del_count > len - start_i) del_count = len - start_i;
} else {
del_count = len - start_i;
}
var deleted_elements = [];
deleted_elements.length = del_count;
// Number of elements to add.
var num_additional_args = 0;
if (num_arguments > 2) {
num_additional_args = num_arguments - 2;
}
var use_simple_splice = true;
if (IS_ARRAY(this) && num_additional_args !== del_count) {
// If we are only deleting/moving a few things near the end of the
// array then the simple version is going to be faster, because it
// doesn't touch most of the array.
var estimated_non_hole_elements = %EstimateNumberOfElements(this);
if (len > 20 && (estimated_non_hole_elements >> 2) < (len - start_i)) {
use_simple_splice = false;
}
}
if (use_simple_splice) {
SimpleSlice(this, start_i, del_count, len, deleted_elements);
SimpleMove(this, start_i, del_count, len, num_additional_args);
} else {
SmartSlice(this, start_i, del_count, len, deleted_elements);
SmartMove(this, start_i, del_count, len, num_additional_args);
}
// Insert the arguments into the resulting array in
// place of the deleted elements.
var i = start_i;
var arguments_index = 2;
var arguments_length = %_ArgumentsLength();
while (arguments_index < arguments_length) {
this[i++] = %_Arguments(arguments_index++);
}
this.length = len - del_count + num_additional_args;
// Return the deleted elements.
return deleted_elements;
}
function ArraySort(comparefn) {
// In-place QuickSort algorithm.
// For short (length <= 22) arrays, insertion sort is used for efficiency.
var custom_compare = IS_FUNCTION(comparefn);
function Compare(x,y) {
if (custom_compare) {
return comparefn.call(null, x, y);
}
if (%_IsSmi(x) && %_IsSmi(y)) {
return %SmiLexicographicCompare(x, y);
}
x = ToString(x);
y = ToString(y);
if (x == y) return 0;
else return x < y ? -1 : 1;
};
function InsertionSort(a, from, to) {
for (var i = from + 1; i < to; i++) {
var element = a[i];
// place element in a[from..i[
// binary search
var min = from;
var max = i;
// The search interval is a[min..max[
while (min < max) {
var mid = min + ((max - min) >> 1);
var order = Compare(a[mid], element);
if (order == 0) {
min = max = mid;
break;
}
if (order < 0) {
min = mid + 1;
} else {
max = mid;
}
}
// place element at position min==max.
for (var j = i; j > min; j--) {
a[j] = a[j - 1];
}
a[min] = element;
}
}
function QuickSort(a, from, to) {
// Insertion sort is faster for short arrays.
if (to - from <= 22) {
InsertionSort(a, from, to);
return;
}
var pivot_index = $floor($random() * (to - from)) + from;
var pivot = a[pivot_index];
// Issue 95: Keep the pivot element out of the comparisons to avoid
// infinite recursion if comparefn(pivot, pivot) != 0.
a[pivot_index] = a[to - 1];
a[to - 1] = pivot;
var low_end = from; // Upper bound of the elements lower than pivot.
var high_start = to - 1; // Lower bound of the elements greater than pivot.
for (var i = from; i < high_start; ) {
var element = a[i];
var order = Compare(element, pivot);
if (order < 0) {
a[i] = a[low_end];
a[low_end] = element;
low_end++;
i++;
} else if (order > 0) {
high_start--;
a[i] = a[high_start];
a[high_start] = element;
} else { // order == 0
i++;
}
}
// Restore the pivot element to its rightful place.
a[to - 1] = a[high_start];
a[high_start] = pivot;
high_start++;
QuickSort(a, from, low_end);
QuickSort(a, high_start, to);
}
var old_length = ToUint32(this.length);
%RemoveArrayHoles(this);
var length = ToUint32(this.length);
// Move undefined elements to the end of the array.
for (var i = 0; i < length; ) {
if (IS_UNDEFINED(this[i])) {
length--;
this[i] = this[length];
this[length] = void 0;
} else {
i++;
}
}
QuickSort(this, 0, length);
// We only changed the length of the this object (in
// RemoveArrayHoles) if it was an array. We are not allowed to set
// the length of the this object if it is not an array because this
// might introduce a new length property.
if (IS_ARRAY(this)) {
this.length = old_length;
}
return this;
}
// The following functions cannot be made efficient on sparse arrays while
// preserving the semantics, since the calls to the receiver function can add
// or delete elements from the array.
function ArrayFilter(f, receiver) {
if (!IS_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]);
}
// Pull out the length so that modifications to the length in the
// loop will not affect the looping.
var length = this.length;
var result = [];
for (var i = 0; i < length; i++) {
var current = this[i];
if (!IS_UNDEFINED(current) || i in this) {
if (f.call(receiver, current, i, this)) result.push(current);
}
}
return result;
}
function ArrayForEach(f, receiver) {
if (!IS_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]);
}
// Pull out the length so that modifications to the length in the
// loop will not affect the looping.
var length = this.length;
for (var i = 0; i < length; i++) {
var current = this[i];
if (!IS_UNDEFINED(current) || i in this) {
f.call(receiver, current, i, this);
}
}
}
// Executes the function once for each element present in the
// array until it finds one where callback returns true.
function ArraySome(f, receiver) {
if (!IS_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]);
}
// Pull out the length so that modifications to the length in the
// loop will not affect the looping.
var length = this.length;
for (var i = 0; i < length; i++) {
var current = this[i];
if (!IS_UNDEFINED(current) || i in this) {
if (f.call(receiver, current, i, this)) return true;
}
}
return false;
}
function ArrayEvery(f, receiver) {
if (!IS_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]);
}
// Pull out the length so that modifications to the length in the
// loop will not affect the looping.
var length = this.length;
for (var i = 0; i < length; i++) {
var current = this[i];
if (!IS_UNDEFINED(current) || i in this) {
if (!f.call(receiver, current, i, this)) return false;
}
}
return true;
}
function ArrayMap(f, receiver) {
if (!IS_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]);
}
// Pull out the length so that modifications to the length in the
// loop will not affect the looping.
var length = this.length;
var result = new $Array(length);
for (var i = 0; i < length; i++) {
var current = this[i];
if (!IS_UNDEFINED(current) || i in this) {
result[i] = f.call(receiver, current, i, this);
}
}
return result;
}
function ArrayIndexOf(element, index) {
var length = this.length;
if (index == null) {
index = 0;
} else {
index = TO_INTEGER(index);
// If index is negative, index from the end of the array.
if (index < 0) index = length + index;
// If index is still negative, search the entire array.
if (index < 0) index = 0;
}
// Lookup through the array.
for (var i = index; i < length; i++) {
var current = this[i];
if (!IS_UNDEFINED(current) || i in this) {
if (current === element) return i;
}
}
return -1;
}
function ArrayLastIndexOf(element, index) {
var length = this.length;
if (index == null) {
index = length - 1;
} else {
index = TO_INTEGER(index);
// If index is negative, index from end of the array.
if (index < 0) index = length + index;
// If index is still negative, do not search the array.
if (index < 0) index = -1;
else if (index >= length) index = length - 1;
}
// Lookup through the array.
for (var i = index; i >= 0; i--) {
var current = this[i];
if (!IS_UNDEFINED(current) || i in this) {
if (current === element) return i;
}
}
return -1;
}
// -------------------------------------------------------------------
function UpdateFunctionLengths(lengths) {
for (var key in lengths) {
%FunctionSetLength(this[key], lengths[key]);
}
}
// -------------------------------------------------------------------
function SetupArray() {
// Setup non-enumerable constructor property on the Array.prototype
// object.
%SetProperty($Array.prototype, "constructor", $Array, DONT_ENUM);
// Setup non-enumerable functions of the Array.prototype object and
// set their names.
InstallFunctions($Array.prototype, DONT_ENUM, $Array(
"toString", ArrayToString,
"toLocaleString", ArrayToLocaleString,
"join", ArrayJoin,
"pop", ArrayPop,
"push", ArrayPush,
"concat", ArrayConcat,
"reverse", ArrayReverse,
"shift", ArrayShift,
"unshift", ArrayUnshift,
"slice", ArraySlice,
"splice", ArraySplice,
"sort", ArraySort,
"filter", ArrayFilter,
"forEach", ArrayForEach,
"some", ArraySome,
"every", ArrayEvery,
"map", ArrayMap,
"indexOf", ArrayIndexOf,
"lastIndexOf", ArrayLastIndexOf
));
// Manipulate the length of some of the functions to meet
// expectations set by ECMA-262 or Mozilla.
UpdateFunctionLengths({
ArrayFilter: 1,
ArrayForEach: 1,
ArraySome: 1,
ArrayEvery: 1,
ArrayMap: 1,
ArrayIndexOf: 1,
ArrayLastIndexOf: 1,
ArrayPush: 1
});
}
SetupArray();

View File

@ -1,243 +0,0 @@
// Copyright (c) 1994-2006 Sun Microsystems Inc.
// All Rights Reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// - Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// - Redistribution 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 Sun Microsystems or the names of contributors may
// be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
// The original source code covered by the above license above has been modified
// significantly by Google Inc.
// Copyright 2006-2008 the V8 project authors. All rights reserved.
#ifndef V8_ASSEMBLER_ARM_INL_H_
#define V8_ASSEMBLER_ARM_INL_H_
#include "assembler-arm.h"
#include "cpu.h"
namespace v8 { namespace internal {
Condition NegateCondition(Condition cc) {
ASSERT(cc != al);
return static_cast<Condition>(cc ^ ne);
}
void RelocInfo::apply(int delta) {
if (RelocInfo::IsInternalReference(rmode_)) {
// absolute code pointer inside code object moves with the code object.
int32_t* p = reinterpret_cast<int32_t*>(pc_);
*p += delta; // relocate entry
}
// We do not use pc relative addressing on ARM, so there is
// nothing else to do.
}
Address RelocInfo::target_address() {
ASSERT(IsCodeTarget(rmode_));
return Assembler::target_address_at(pc_);
}
void RelocInfo::set_target_address(Address target) {
ASSERT(IsCodeTarget(rmode_));
Assembler::set_target_address_at(pc_, target);
}
Object* RelocInfo::target_object() {
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
return reinterpret_cast<Object*>(Assembler::target_address_at(pc_));
}
Object** RelocInfo::target_object_address() {
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
return reinterpret_cast<Object**>(Assembler::target_address_address_at(pc_));
}
void RelocInfo::set_target_object(Object* target) {
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
Assembler::set_target_address_at(pc_, reinterpret_cast<Address>(target));
}
Address* RelocInfo::target_reference_address() {
ASSERT(rmode_ == EXTERNAL_REFERENCE);
return reinterpret_cast<Address*>(pc_);
}
Address RelocInfo::call_address() {
ASSERT(is_call_instruction());
UNIMPLEMENTED();
return NULL;
}
void RelocInfo::set_call_address(Address target) {
ASSERT(is_call_instruction());
UNIMPLEMENTED();
}
Object* RelocInfo::call_object() {
ASSERT(is_call_instruction());
UNIMPLEMENTED();
return NULL;
}
Object** RelocInfo::call_object_address() {
ASSERT(is_call_instruction());
UNIMPLEMENTED();
return NULL;
}
void RelocInfo::set_call_object(Object* target) {
ASSERT(is_call_instruction());
UNIMPLEMENTED();
}
bool RelocInfo::is_call_instruction() {
UNIMPLEMENTED();
return false;
}
Operand::Operand(int32_t immediate, RelocInfo::Mode rmode) {
rm_ = no_reg;
imm32_ = immediate;
rmode_ = rmode;
}
Operand::Operand(const char* s) {
rm_ = no_reg;
imm32_ = reinterpret_cast<int32_t>(s);
rmode_ = RelocInfo::EMBEDDED_STRING;
}
Operand::Operand(const ExternalReference& f) {
rm_ = no_reg;
imm32_ = reinterpret_cast<int32_t>(f.address());
rmode_ = RelocInfo::EXTERNAL_REFERENCE;
}
Operand::Operand(Object** opp) {
rm_ = no_reg;
imm32_ = reinterpret_cast<int32_t>(opp);
rmode_ = RelocInfo::NONE;
}
Operand::Operand(Context** cpp) {
rm_ = no_reg;
imm32_ = reinterpret_cast<int32_t>(cpp);
rmode_ = RelocInfo::NONE;
}
Operand::Operand(Smi* value) {
rm_ = no_reg;
imm32_ = reinterpret_cast<intptr_t>(value);
rmode_ = RelocInfo::NONE;
}
Operand::Operand(Register rm) {
rm_ = rm;
rs_ = no_reg;
shift_op_ = LSL;
shift_imm_ = 0;
}
bool Operand::is_reg() const {
return rm_.is_valid() &&
rs_.is(no_reg) &&
shift_op_ == LSL &&
shift_imm_ == 0;
}
void Assembler::CheckBuffer() {
if (buffer_space() <= kGap) {
GrowBuffer();
}
if (pc_offset() > next_buffer_check_) {
CheckConstPool(false, true);
}
}
void Assembler::emit(Instr x) {
CheckBuffer();
*reinterpret_cast<Instr*>(pc_) = x;
pc_ += kInstrSize;
}
Address Assembler::target_address_address_at(Address pc) {
Instr instr = Memory::int32_at(pc);
// Verify that the instruction at pc is a ldr<cond> <Rd>, [pc +/- offset_12].
ASSERT((instr & 0x0f7f0000) == 0x051f0000);
int offset = instr & 0xfff; // offset_12 is unsigned
if ((instr & (1 << 23)) == 0) offset = -offset; // U bit defines offset sign
// Verify that the constant pool comes after the instruction referencing it.
ASSERT(offset >= -4);
return pc + offset + 8;
}
Address Assembler::target_address_at(Address pc) {
return Memory::Address_at(target_address_address_at(pc));
}
void Assembler::set_target_address_at(Address pc, Address target) {
Memory::Address_at(target_address_address_at(pc)) = target;
// Intuitively, we would think it is necessary to flush the instruction cache
// after patching a target address in the code as follows:
// CPU::FlushICache(pc, sizeof(target));
// However, on ARM, no instruction was actually patched by the assignment
// above; the target address is not part of an instruction, it is patched in
// the constant pool and is read via a data access; the instruction accessing
// this address in the constant pool remains unchanged.
}
} } // namespace v8::internal
#endif // V8_ASSEMBLER_ARM_INL_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,784 +0,0 @@
// Copyright (c) 1994-2006 Sun Microsystems Inc.
// All Rights Reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// - Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// - Redistribution 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 Sun Microsystems or the names of contributors may
// be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
// The original source code covered by the above license above has been modified
// significantly by Google Inc.
// Copyright 2006-2008 the V8 project authors. All rights reserved.
// A light-weight ARM Assembler
// Generates user mode instructions for the ARM architecture up to version 5
#ifndef V8_ASSEMBLER_ARM_H_
#define V8_ASSEMBLER_ARM_H_
#include "assembler.h"
namespace v8 { namespace internal {
// CPU Registers.
//
// 1) We would prefer to use an enum, but enum values are assignment-
// compatible with int, which has caused code-generation bugs.
//
// 2) We would prefer to use a class instead of a struct but we don't like
// the register initialization to depend on the particular initialization
// order (which appears to be different on OS X, Linux, and Windows for the
// installed versions of C++ we tried). Using a struct permits C-style
// "initialization". Also, the Register objects cannot be const as this
// forces initialization stubs in MSVC, making us dependent on initialization
// order.
//
// 3) By not using an enum, we are possibly preventing the compiler from
// doing certain constant folds, which may significantly reduce the
// code generated for some assembly instructions (because they boil down
// to a few constants). If this is a problem, we could change the code
// such that we use an enum in optimized mode, and the struct in debug
// mode. This way we get the compile-time error checking in debug mode
// and best performance in optimized code.
//
// Core register
struct Register {
bool is_valid() const { return 0 <= code_ && code_ < 16; }
bool is(Register reg) const { return code_ == reg.code_; }
int code() const {
ASSERT(is_valid());
return code_;
}
int bit() const {
ASSERT(is_valid());
return 1 << code_;
}
// (unfortunately we can't make this private in a struct)
int code_;
};
extern Register no_reg;
extern Register r0;
extern Register r1;
extern Register r2;
extern Register r3;
extern Register r4;
extern Register r5;
extern Register r6;
extern Register r7;
extern Register r8;
extern Register r9;
extern Register r10;
extern Register fp;
extern Register ip;
extern Register sp;
extern Register lr;
extern Register pc;
// Coprocessor register
struct CRegister {
bool is_valid() const { return 0 <= code_ && code_ < 16; }
bool is(CRegister creg) const { return code_ == creg.code_; }
int code() const {
ASSERT(is_valid());
return code_;
}
int bit() const {
ASSERT(is_valid());
return 1 << code_;
}
// (unfortunately we can't make this private in a struct)
int code_;
};
extern CRegister no_creg;
extern CRegister cr0;
extern CRegister cr1;
extern CRegister cr2;
extern CRegister cr3;
extern CRegister cr4;
extern CRegister cr5;
extern CRegister cr6;
extern CRegister cr7;
extern CRegister cr8;
extern CRegister cr9;
extern CRegister cr10;
extern CRegister cr11;
extern CRegister cr12;
extern CRegister cr13;
extern CRegister cr14;
extern CRegister cr15;
// Coprocessor number
enum Coprocessor {
p0 = 0,
p1 = 1,
p2 = 2,
p3 = 3,
p4 = 4,
p5 = 5,
p6 = 6,
p7 = 7,
p8 = 8,
p9 = 9,
p10 = 10,
p11 = 11,
p12 = 12,
p13 = 13,
p14 = 14,
p15 = 15
};
// Condition field in instructions
enum Condition {
eq = 0 << 28,
ne = 1 << 28,
cs = 2 << 28,
hs = 2 << 28,
cc = 3 << 28,
lo = 3 << 28,
mi = 4 << 28,
pl = 5 << 28,
vs = 6 << 28,
vc = 7 << 28,
hi = 8 << 28,
ls = 9 << 28,
ge = 10 << 28,
lt = 11 << 28,
gt = 12 << 28,
le = 13 << 28,
al = 14 << 28
};
// Returns the equivalent of !cc.
INLINE(Condition NegateCondition(Condition cc));
// Corresponds to transposing the operands of a comparison.
inline Condition ReverseCondition(Condition cc) {
switch (cc) {
case lo:
return hi;
case hi:
return lo;
case hs:
return ls;
case ls:
return hs;
case lt:
return gt;
case gt:
return lt;
case ge:
return le;
case le:
return ge;
default:
return cc;
};
}
// The pc store offset may be 8 or 12 depending on the processor implementation.
int PcStoreOffset();
// -----------------------------------------------------------------------------
// Addressing modes and instruction variants
// Shifter operand shift operation
enum ShiftOp {
LSL = 0 << 5,
LSR = 1 << 5,
ASR = 2 << 5,
ROR = 3 << 5,
RRX = -1
};
// Condition code updating mode
enum SBit {
SetCC = 1 << 20, // set condition code
LeaveCC = 0 << 20 // leave condition code unchanged
};
// Status register selection
enum SRegister {
CPSR = 0 << 22,
SPSR = 1 << 22
};
// Status register fields
enum SRegisterField {
CPSR_c = CPSR | 1 << 16,
CPSR_x = CPSR | 1 << 17,
CPSR_s = CPSR | 1 << 18,
CPSR_f = CPSR | 1 << 19,
SPSR_c = SPSR | 1 << 16,
SPSR_x = SPSR | 1 << 17,
SPSR_s = SPSR | 1 << 18,
SPSR_f = SPSR | 1 << 19
};
// Status register field mask (or'ed SRegisterField enum values)
typedef uint32_t SRegisterFieldMask;
// Memory operand addressing mode
enum AddrMode {
// bit encoding P U W
Offset = (8|4|0) << 21, // offset (without writeback to base)
PreIndex = (8|4|1) << 21, // pre-indexed addressing with writeback
PostIndex = (0|4|0) << 21, // post-indexed addressing with writeback
NegOffset = (8|0|0) << 21, // negative offset (without writeback to base)
NegPreIndex = (8|0|1) << 21, // negative pre-indexed with writeback
NegPostIndex = (0|0|0) << 21 // negative post-indexed with writeback
};
// Load/store multiple addressing mode
enum BlockAddrMode {
// bit encoding P U W
da = (0|0|0) << 21, // decrement after
ia = (0|4|0) << 21, // increment after
db = (8|0|0) << 21, // decrement before
ib = (8|4|0) << 21, // increment before
da_w = (0|0|1) << 21, // decrement after with writeback to base
ia_w = (0|4|1) << 21, // increment after with writeback to base
db_w = (8|0|1) << 21, // decrement before with writeback to base
ib_w = (8|4|1) << 21 // increment before with writeback to base
};
// Coprocessor load/store operand size
enum LFlag {
Long = 1 << 22, // long load/store coprocessor
Short = 0 << 22 // short load/store coprocessor
};
// -----------------------------------------------------------------------------
// Machine instruction Operands
// Class Operand represents a shifter operand in data processing instructions
class Operand BASE_EMBEDDED {
public:
// immediate
INLINE(explicit Operand(int32_t immediate,
RelocInfo::Mode rmode = RelocInfo::NONE));
INLINE(explicit Operand(const ExternalReference& f));
INLINE(explicit Operand(const char* s));
INLINE(explicit Operand(Object** opp));
INLINE(explicit Operand(Context** cpp));
explicit Operand(Handle<Object> handle);
INLINE(explicit Operand(Smi* value));
// rm
INLINE(explicit Operand(Register rm));
// rm <shift_op> shift_imm
explicit Operand(Register rm, ShiftOp shift_op, int shift_imm);
// rm <shift_op> rs
explicit Operand(Register rm, ShiftOp shift_op, Register rs);
// Return true if this is a register operand.
INLINE(bool is_reg() const);
Register rm() const { return rm_; }
private:
Register rm_;
Register rs_;
ShiftOp shift_op_;
int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
int32_t imm32_; // valid if rm_ == no_reg
RelocInfo::Mode rmode_;
friend class Assembler;
};
// Class MemOperand represents a memory operand in load and store instructions
class MemOperand BASE_EMBEDDED {
public:
// [rn +/- offset] Offset/NegOffset
// [rn +/- offset]! PreIndex/NegPreIndex
// [rn], +/- offset PostIndex/NegPostIndex
// offset is any signed 32-bit value; offset is first loaded to register ip if
// it does not fit the addressing mode (12-bit unsigned and sign bit)
explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset);
// [rn +/- rm] Offset/NegOffset
// [rn +/- rm]! PreIndex/NegPreIndex
// [rn], +/- rm PostIndex/NegPostIndex
explicit MemOperand(Register rn, Register rm, AddrMode am = Offset);
// [rn +/- rm <shift_op> shift_imm] Offset/NegOffset
// [rn +/- rm <shift_op> shift_imm]! PreIndex/NegPreIndex
// [rn], +/- rm <shift_op> shift_imm PostIndex/NegPostIndex
explicit MemOperand(Register rn, Register rm,
ShiftOp shift_op, int shift_imm, AddrMode am = Offset);
private:
Register rn_; // base
Register rm_; // register offset
int32_t offset_; // valid if rm_ == no_reg
ShiftOp shift_op_;
int shift_imm_; // valid if rm_ != no_reg && rs_ == no_reg
AddrMode am_; // bits P, U, and W
friend class Assembler;
};
typedef int32_t Instr;
class Assembler : public Malloced {
public:
// Create an assembler. Instructions and relocation information are emitted
// into a buffer, with the instructions starting from the beginning and the
// relocation information starting from the end of the buffer. See CodeDesc
// for a detailed comment on the layout (globals.h).
//
// If the provided buffer is NULL, the assembler allocates and grows its own
// buffer, and buffer_size determines the initial buffer size. The buffer is
// owned by the assembler and deallocated upon destruction of the assembler.
//
// If the provided buffer is not NULL, the assembler uses the provided buffer
// for code generation and assumes its size to be buffer_size. If the buffer
// is too small, a fatal error occurs. No deallocation of the buffer is done
// upon destruction of the assembler.
Assembler(void* buffer, int buffer_size);
~Assembler();
// GetCode emits any pending (non-emitted) code and fills the descriptor
// desc. GetCode() is idempotent; it returns the same result if no other
// Assembler functions are invoked inbetween GetCode() calls.
void GetCode(CodeDesc* desc);
// Label operations & relative jumps (PPUM Appendix D)
//
// Takes a branch opcode (cc) and a label (L) and generates
// either a backward branch or a forward branch and links it
// to the label fixup chain. Usage:
//
// Label L; // unbound label
// j(cc, &L); // forward branch to unbound label
// bind(&L); // bind label to the current pc
// j(cc, &L); // backward branch to bound label
// bind(&L); // illegal: a label may be bound only once
//
// Note: The same Label can be used for forward and backward branches
// but it may be bound only once.
void bind(Label* L); // binds an unbound label L to the current code position
// Returns the branch offset to the given label from the current code position
// Links the label to the current position if it is still unbound
// Manages the jump elimination optimization if the second parameter is true.
int branch_offset(Label* L, bool jump_elimination_allowed);
// Return the address in the constant pool of the code target address used by
// the branch/call instruction at pc.
INLINE(static Address target_address_address_at(Address pc));
// Read/Modify the code target address in the branch/call instruction at pc.
INLINE(static Address target_address_at(Address pc));
INLINE(static void set_target_address_at(Address pc, Address target));
// Distance between the instruction referring to the address of the call
// target (ldr pc, [target addr in const pool]) and the return address
static const int kTargetAddrToReturnAddrDist = sizeof(Instr);
// ---------------------------------------------------------------------------
// Code generation
// Insert the smallest number of nop instructions
// possible to align the pc offset to a multiple
// of m. m must be a power of 2 (>= 4).
void Align(int m);
// Branch instructions
void b(int branch_offset, Condition cond = al);
void bl(int branch_offset, Condition cond = al);
void blx(int branch_offset); // v5 and above
void blx(Register target, Condition cond = al); // v5 and above
void bx(Register target, Condition cond = al); // v5 and above, plus v4t
// Convenience branch instructions using labels
void b(Label* L, Condition cond = al) {
b(branch_offset(L, cond == al), cond);
}
void b(Condition cond, Label* L) { b(branch_offset(L, cond == al), cond); }
void bl(Label* L, Condition cond = al) { bl(branch_offset(L, false), cond); }
void bl(Condition cond, Label* L) { bl(branch_offset(L, false), cond); }
void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above
// Data-processing instructions
void and_(Register dst, Register src1, const Operand& src2,
SBit s = LeaveCC, Condition cond = al);
void eor(Register dst, Register src1, const Operand& src2,
SBit s = LeaveCC, Condition cond = al);
void sub(Register dst, Register src1, const Operand& src2,
SBit s = LeaveCC, Condition cond = al);
void sub(Register dst, Register src1, Register src2,
SBit s = LeaveCC, Condition cond = al) {
sub(dst, src1, Operand(src2), s, cond);
}
void rsb(Register dst, Register src1, const Operand& src2,
SBit s = LeaveCC, Condition cond = al);
void add(Register dst, Register src1, const Operand& src2,
SBit s = LeaveCC, Condition cond = al);
void adc(Register dst, Register src1, const Operand& src2,
SBit s = LeaveCC, Condition cond = al);
void sbc(Register dst, Register src1, const Operand& src2,
SBit s = LeaveCC, Condition cond = al);
void rsc(Register dst, Register src1, const Operand& src2,
SBit s = LeaveCC, Condition cond = al);
void tst(Register src1, const Operand& src2, Condition cond = al);
void tst(Register src1, Register src2, Condition cond = al) {
tst(src1, Operand(src2), cond);
}
void teq(Register src1, const Operand& src2, Condition cond = al);
void cmp(Register src1, const Operand& src2, Condition cond = al);
void cmp(Register src1, Register src2, Condition cond = al) {
cmp(src1, Operand(src2), cond);
}
void cmn(Register src1, const Operand& src2, Condition cond = al);
void orr(Register dst, Register src1, const Operand& src2,
SBit s = LeaveCC, Condition cond = al);
void orr(Register dst, Register src1, Register src2,
SBit s = LeaveCC, Condition cond = al) {
orr(dst, src1, Operand(src2), s, cond);
}
void mov(Register dst, const Operand& src,
SBit s = LeaveCC, Condition cond = al);
void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
mov(dst, Operand(src), s, cond);
}
void bic(Register dst, Register src1, const Operand& src2,
SBit s = LeaveCC, Condition cond = al);
void mvn(Register dst, const Operand& src,
SBit s = LeaveCC, Condition cond = al);
// Multiply instructions
void mla(Register dst, Register src1, Register src2, Register srcA,
SBit s = LeaveCC, Condition cond = al);
void mul(Register dst, Register src1, Register src2,
SBit s = LeaveCC, Condition cond = al);
void smlal(Register dstL, Register dstH, Register src1, Register src2,
SBit s = LeaveCC, Condition cond = al);
void smull(Register dstL, Register dstH, Register src1, Register src2,
SBit s = LeaveCC, Condition cond = al);
void umlal(Register dstL, Register dstH, Register src1, Register src2,
SBit s = LeaveCC, Condition cond = al);
void umull(Register dstL, Register dstH, Register src1, Register src2,
SBit s = LeaveCC, Condition cond = al);
// Miscellaneous arithmetic instructions
void clz(Register dst, Register src, Condition cond = al); // v5 and above
// Status register access instructions
void mrs(Register dst, SRegister s, Condition cond = al);
void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al);
// Load/Store instructions
void ldr(Register dst, const MemOperand& src, Condition cond = al);
void str(Register src, const MemOperand& dst, Condition cond = al);
void ldrb(Register dst, const MemOperand& src, Condition cond = al);
void strb(Register src, const MemOperand& dst, Condition cond = al);
void ldrh(Register dst, const MemOperand& src, Condition cond = al);
void strh(Register src, const MemOperand& dst, Condition cond = al);
void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
// Load/Store multiple instructions
void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
// Semaphore instructions
void swp(Register dst, Register src, Register base, Condition cond = al);
void swpb(Register dst, Register src, Register base, Condition cond = al);
// Exception-generating instructions and debugging support
void stop(const char* msg);
void bkpt(uint32_t imm16); // v5 and above
void swi(uint32_t imm24, Condition cond = al);
// Coprocessor instructions
void cdp(Coprocessor coproc, int opcode_1,
CRegister crd, CRegister crn, CRegister crm,
int opcode_2, Condition cond = al);
void cdp2(Coprocessor coproc, int opcode_1,
CRegister crd, CRegister crn, CRegister crm,
int opcode_2); // v5 and above
void mcr(Coprocessor coproc, int opcode_1,
Register rd, CRegister crn, CRegister crm,
int opcode_2 = 0, Condition cond = al);
void mcr2(Coprocessor coproc, int opcode_1,
Register rd, CRegister crn, CRegister crm,
int opcode_2 = 0); // v5 and above
void mrc(Coprocessor coproc, int opcode_1,
Register rd, CRegister crn, CRegister crm,
int opcode_2 = 0, Condition cond = al);
void mrc2(Coprocessor coproc, int opcode_1,
Register rd, CRegister crn, CRegister crm,
int opcode_2 = 0); // v5 and above
void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src,
LFlag l = Short, Condition cond = al);
void ldc(Coprocessor coproc, CRegister crd, Register base, int option,
LFlag l = Short, Condition cond = al);
void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
LFlag l = Short); // v5 and above
void ldc2(Coprocessor coproc, CRegister crd, Register base, int option,
LFlag l = Short); // v5 and above
void stc(Coprocessor coproc, CRegister crd, const MemOperand& dst,
LFlag l = Short, Condition cond = al);
void stc(Coprocessor coproc, CRegister crd, Register base, int option,
LFlag l = Short, Condition cond = al);
void stc2(Coprocessor coproc, CRegister crd, const MemOperand& dst,
LFlag l = Short); // v5 and above
void stc2(Coprocessor coproc, CRegister crd, Register base, int option,
LFlag l = Short); // v5 and above
// Pseudo instructions
void nop() { mov(r0, Operand(r0)); }
void push(Register src) {
str(src, MemOperand(sp, 4, NegPreIndex), al);
}
void pop(Register dst) {
ldr(dst, MemOperand(sp, 4, PostIndex), al);
}
void pop() {
add(sp, sp, Operand(kPointerSize));
}
// Load effective address of memory operand x into register dst
void lea(Register dst, const MemOperand& x,
SBit s = LeaveCC, Condition cond = al);
// Jump unconditionally to given label.
void jmp(Label* L) { b(L, al); }
// Debugging
// Record a comment relocation entry that can be used by a disassembler.
// Use --debug_code to enable.
void RecordComment(const char* msg);
void RecordPosition(int pos);
void RecordStatementPosition(int pos);
int pc_offset() const { return pc_ - buffer_; }
int last_position() const { return last_position_; }
bool last_position_is_statement() const {
return last_position_is_statement_;
}
// Temporary helper function. Used by codegen.cc.
int last_statement_position() const { return last_position_; }
protected:
int buffer_space() const { return reloc_info_writer.pos() - pc_; }
// Read/patch instructions
Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
void instr_at_put(byte* pc, Instr instr) {
*reinterpret_cast<Instr*>(pc) = instr;
}
Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
void instr_at_put(int pos, Instr instr) {
*reinterpret_cast<Instr*>(buffer_ + pos) = instr;
}
// Decode branch instruction at pos and return branch target pos
int target_at(int pos);
// Patch branch instruction at pos to branch to given branch target pos
void target_at_put(int pos, int target_pos);
private:
// Code buffer:
// The buffer into which code and relocation info are generated.
byte* buffer_;
int buffer_size_;
// True if the assembler owns the buffer, false if buffer is external.
bool own_buffer_;
// Buffer size and constant pool distance are checked together at regular
// intervals of kBufferCheckInterval emitted bytes
static const int kBufferCheckInterval = 1*KB/2;
int next_buffer_check_; // pc offset of next buffer check
// Code generation
static const int kInstrSize = sizeof(Instr); // signed size
// The relocation writer's position is at least kGap bytes below the end of
// the generated instructions. This is so that multi-instruction sequences do
// not have to check for overflow. The same is true for writes of large
// relocation info entries.
static const int kGap = 32;
byte* pc_; // the program counter; moves forward
// Constant pool generation
// Pools are emitted in the instruction stream, preferably after unconditional
// jumps or after returns from functions (in dead code locations).
// If a long code sequence does not contain unconditional jumps, it is
// necessary to emit the constant pool before the pool gets too far from the
// location it is accessed from. In this case, we emit a jump over the emitted
// constant pool.
// Constants in the pool may be addresses of functions that gets relocated;
// if so, a relocation info entry is associated to the constant pool entry.
// Repeated checking whether the constant pool should be emitted is rather
// expensive. By default we only check again once a number of instructions
// has been generated. That also means that the sizing of the buffers is not
// an exact science, and that we rely on some slop to not overrun buffers.
static const int kCheckConstIntervalInst = 32;
static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize;
// Pools are emitted after function return and in dead code at (more or less)
// regular intervals of kDistBetweenPools bytes
static const int kDistBetweenPools = 1*KB;
// Constants in pools are accessed via pc relative addressing, which can
// reach +/-4KB thereby defining a maximum distance between the instruction
// and the accessed constant. We satisfy this constraint by limiting the
// distance between pools.
static const int kMaxDistBetweenPools = 4*KB - 2*kBufferCheckInterval;
// Emission of the constant pool may be blocked in some code sequences
int no_const_pool_before_; // block emission before this pc offset
// Keep track of the last emitted pool to guarantee a maximal distance
int last_const_pool_end_; // pc offset following the last constant pool
// Relocation info generation
// Each relocation is encoded as a variable size value
static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
RelocInfoWriter reloc_info_writer;
// Relocation info records are also used during code generation as temporary
// containers for constants and code target addresses until they are emitted
// to the constant pool. These pending relocation info records are temporarily
// stored in a separate buffer until a constant pool is emitted.
// If every instruction in a long sequence is accessing the pool, we need one
// pending relocation entry per instruction.
static const int kMaxNumPRInfo = kMaxDistBetweenPools/kInstrSize;
RelocInfo prinfo_[kMaxNumPRInfo]; // the buffer of pending relocation info
int num_prinfo_; // number of pending reloc info entries in the buffer
// The bound position, before this we cannot do instruction elimination.
int last_bound_pos_;
// source position information
int last_position_;
bool last_position_is_statement_;
// Code emission
inline void CheckBuffer();
void GrowBuffer();
inline void emit(Instr x);
// Instruction generation
void addrmod1(Instr instr, Register rn, Register rd, const Operand& x);
void addrmod2(Instr instr, Register rd, const MemOperand& x);
void addrmod3(Instr instr, Register rd, const MemOperand& x);
void addrmod4(Instr instr, Register rn, RegList rl);
void addrmod5(Instr instr, CRegister crd, const MemOperand& x);
// Labels
void print(Label* L);
void bind_to(Label* L, int pos);
void link_to(Label* L, Label* appendix);
void next(Label* L);
// Record reloc info for current pc_
void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
// Check if is time to emit a constant pool for pending reloc info entries
void CheckConstPool(bool force_emit, bool require_jump);
// Block the emission of the constant pool before pc_offset
void BlockConstPoolBefore(int pc_offset) {
if (no_const_pool_before_ < pc_offset) no_const_pool_before_ = pc_offset;
}
};
} } // namespace v8::internal
#endif // V8_ASSEMBLER_ARM_H_

View File

@ -1,266 +0,0 @@
// Copyright (c) 1994-2006 Sun Microsystems Inc.
// All Rights Reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// - Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// - Redistribution 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 Sun Microsystems or the names of contributors may
// be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// The original source code covered by the above license above has been
// modified significantly by Google Inc.
// Copyright 2006-2008 the V8 project authors. All rights reserved.
// A light-weight IA32 Assembler.
#ifndef V8_ASSEMBLER_IA32_INL_H_
#define V8_ASSEMBLER_IA32_INL_H_
#include "cpu.h"
namespace v8 { namespace internal {
Condition NegateCondition(Condition cc) {
return static_cast<Condition>(cc ^ 1);
}
// The modes possibly affected by apply must be in kApplyMask.
void RelocInfo::apply(int delta) {
if (rmode_ == RUNTIME_ENTRY || IsCodeTarget(rmode_)) {
int32_t* p = reinterpret_cast<int32_t*>(pc_);
*p -= delta; // relocate entry
} else if (rmode_ == JS_RETURN && is_call_instruction()) {
// Special handling of js_return when a break point is set (call
// instruction has been inserted).
int32_t* p = reinterpret_cast<int32_t*>(pc_ + 1);
*p -= delta; // relocate entry
} else if (IsInternalReference(rmode_)) {
// absolute code pointer inside code object moves with the code object.
int32_t* p = reinterpret_cast<int32_t*>(pc_);
*p += delta; // relocate entry
}
}
Address RelocInfo::target_address() {
ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
return Assembler::target_address_at(pc_);
}
void RelocInfo::set_target_address(Address target) {
ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
Assembler::set_target_address_at(pc_, target);
}
Object* RelocInfo::target_object() {
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
return *reinterpret_cast<Object**>(pc_);
}
Object** RelocInfo::target_object_address() {
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
return reinterpret_cast<Object**>(pc_);
}
void RelocInfo::set_target_object(Object* target) {
ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
*reinterpret_cast<Object**>(pc_) = target;
}
Address* RelocInfo::target_reference_address() {
ASSERT(rmode_ == RelocInfo::EXTERNAL_REFERENCE);
return reinterpret_cast<Address*>(pc_);
}
Address RelocInfo::call_address() {
ASSERT(is_call_instruction());
return Assembler::target_address_at(pc_ + 1);
}
void RelocInfo::set_call_address(Address target) {
ASSERT(is_call_instruction());
Assembler::set_target_address_at(pc_ + 1, target);
}
Object* RelocInfo::call_object() {
ASSERT(is_call_instruction());
return *call_object_address();
}
Object** RelocInfo::call_object_address() {
ASSERT(is_call_instruction());
return reinterpret_cast<Object**>(pc_ + 1);
}
void RelocInfo::set_call_object(Object* target) {
ASSERT(is_call_instruction());
*call_object_address() = target;
}
bool RelocInfo::is_call_instruction() {
return *pc_ == 0xE8;
}
Immediate::Immediate(int x) {
x_ = x;
rmode_ = RelocInfo::NONE;
}
Immediate::Immediate(const ExternalReference& ext) {
x_ = reinterpret_cast<int32_t>(ext.address());
rmode_ = RelocInfo::EXTERNAL_REFERENCE;
}
Immediate::Immediate(const char* s) {
x_ = reinterpret_cast<int32_t>(s);
rmode_ = RelocInfo::EMBEDDED_STRING;
}
Immediate::Immediate(Handle<Object> handle) {
// Verify all Objects referred by code are NOT in new space.
Object* obj = *handle;
ASSERT(!Heap::InNewSpace(obj));
if (obj->IsHeapObject()) {
x_ = reinterpret_cast<intptr_t>(handle.location());
rmode_ = RelocInfo::EMBEDDED_OBJECT;
} else {
// no relocation needed
x_ = reinterpret_cast<intptr_t>(obj);
rmode_ = RelocInfo::NONE;
}
}
Immediate::Immediate(Smi* value) {
x_ = reinterpret_cast<intptr_t>(value);
rmode_ = RelocInfo::NONE;
}
void Assembler::emit(uint32_t x) {
*reinterpret_cast<uint32_t*>(pc_) = x;
pc_ += sizeof(uint32_t);
}
void Assembler::emit(Handle<Object> handle) {
// Verify all Objects referred by code are NOT in new space.
Object* obj = *handle;
ASSERT(!Heap::InNewSpace(obj));
if (obj->IsHeapObject()) {
emit(reinterpret_cast<intptr_t>(handle.location()),
RelocInfo::EMBEDDED_OBJECT);
} else {
// no relocation needed
emit(reinterpret_cast<intptr_t>(obj));
}
}
void Assembler::emit(uint32_t x, RelocInfo::Mode rmode) {
if (rmode != RelocInfo::NONE) RecordRelocInfo(rmode);
emit(x);
}
void Assembler::emit(const Immediate& x) {
if (x.rmode_ != RelocInfo::NONE) RecordRelocInfo(x.rmode_);
emit(x.x_);
}
Address Assembler::target_address_at(Address pc) {
return pc + sizeof(int32_t) + *reinterpret_cast<int32_t*>(pc);
}
void Assembler::set_target_address_at(Address pc, Address target) {
int32_t* p = reinterpret_cast<int32_t*>(pc);
*p = target - (pc + sizeof(int32_t));
CPU::FlushICache(p, sizeof(int32_t));
}
Displacement Assembler::disp_at(Label* L) {
return Displacement(long_at(L->pos()));
}
void Assembler::disp_at_put(Label* L, Displacement disp) {
long_at_put(L->pos(), disp.data());
}
void Assembler::emit_disp(Label* L, Displacement::Type type) {
Displacement disp(L, type);
L->link_to(pc_offset());
emit(static_cast<int>(disp.data()));
}
void Operand::set_modrm(int mod, // reg == 0
Register rm) {
ASSERT((mod & -4) == 0);
buf_[0] = mod << 6 | rm.code();
len_ = 1;
}
void Operand::set_dispr(int32_t disp, RelocInfo::Mode rmode) {
ASSERT(len_ == 1 || len_ == 2);
*reinterpret_cast<int32_t*>(&buf_[len_]) = disp;
len_ += sizeof(int32_t);
rmode_ = rmode;
}
Operand::Operand(Register reg) {
// reg
set_modrm(3, reg);
}
Operand::Operand(int32_t disp, RelocInfo::Mode rmode) {
// [disp/r]
set_modrm(0, ebp);
set_dispr(disp, rmode);
}
} } // namespace v8::internal
#endif // V8_ASSEMBLER_IA32_INL_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,811 +0,0 @@
// Copyright (c) 1994-2006 Sun Microsystems Inc.
// All Rights Reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// - Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// - Redistribution 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 Sun Microsystems or the names of contributors may
// be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// The original source code covered by the above license above has been
// modified significantly by Google Inc.
// Copyright 2006-2008 the V8 project authors. All rights reserved.
// A light-weight IA32 Assembler.
#ifndef V8_ASSEMBLER_IA32_H_
#define V8_ASSEMBLER_IA32_H_
namespace v8 { namespace internal {
// CPU Registers.
//
// 1) We would prefer to use an enum, but enum values are assignment-
// compatible with int, which has caused code-generation bugs.
//
// 2) We would prefer to use a class instead of a struct but we don't like
// the register initialization to depend on the particular initialization
// order (which appears to be different on OS X, Linux, and Windows for the
// installed versions of C++ we tried). Using a struct permits C-style
// "initialization". Also, the Register objects cannot be const as this
// forces initialization stubs in MSVC, making us dependent on initialization
// order.
//
// 3) By not using an enum, we are possibly preventing the compiler from
// doing certain constant folds, which may significantly reduce the
// code generated for some assembly instructions (because they boil down
// to a few constants). If this is a problem, we could change the code
// such that we use an enum in optimized mode, and the struct in debug
// mode. This way we get the compile-time error checking in debug mode
// and best performance in optimized code.
//
struct Register {
bool is_valid() const { return 0 <= code_ && code_ < 8; }
bool is(Register reg) const { return code_ == reg.code_; }
int code() const {
ASSERT(is_valid());
return code_;
}
int bit() const {
ASSERT(is_valid());
return 1 << code_;
}
// (unfortunately we can't make this private in a struct)
int code_;
};
extern Register eax;
extern Register ecx;
extern Register edx;
extern Register ebx;
extern Register esp;
extern Register ebp;
extern Register esi;
extern Register edi;
extern Register no_reg;
struct XMMRegister {
bool is_valid() const { return 0 <= code_ && code_ < 2; } // currently
int code() const {
ASSERT(is_valid());
return code_;
}
int code_;
};
extern XMMRegister xmm0;
extern XMMRegister xmm1;
extern XMMRegister xmm2;
extern XMMRegister xmm3;
extern XMMRegister xmm4;
extern XMMRegister xmm5;
extern XMMRegister xmm6;
extern XMMRegister xmm7;
enum Condition {
// any value < 0 is considered no_condition
no_condition = -1,
overflow = 0,
no_overflow = 1,
below = 2,
above_equal = 3,
equal = 4,
not_equal = 5,
below_equal = 6,
above = 7,
sign = 8,
not_sign = 9,
parity_even = 10,
parity_odd = 11,
less = 12,
greater_equal = 13,
less_equal = 14,
greater = 15,
// aliases
zero = equal,
not_zero = not_equal,
negative = sign,
positive = not_sign
};
// Returns the equivalent of !cc.
// Negation of the default no_condition (-1) results in a non-default
// no_condition value (-2). As long as tests for no_condition check
// for condition < 0, this will work as expected.
inline Condition NegateCondition(Condition cc);
// Corresponds to transposing the operands of a comparison.
inline Condition ReverseCondition(Condition cc) {
switch (cc) {
case below:
return above;
case above:
return below;
case above_equal:
return below_equal;
case below_equal:
return above_equal;
case less:
return greater;
case greater:
return less;
case greater_equal:
return less_equal;
case less_equal:
return greater_equal;
default:
return cc;
};
}
enum Hint {
no_hint = 0,
not_taken = 0x2e,
taken = 0x3e
};
// -----------------------------------------------------------------------------
// Machine instruction Immediates
class Immediate BASE_EMBEDDED {
public:
inline explicit Immediate(int x);
inline explicit Immediate(const char* s);
inline explicit Immediate(const ExternalReference& ext);
inline explicit Immediate(Handle<Object> handle);
inline explicit Immediate(Smi* value);
bool is_zero() const { return x_ == 0 && rmode_ == RelocInfo::NONE; }
bool is_int8() const {
return -128 <= x_ && x_ < 128 && rmode_ == RelocInfo::NONE;
}
private:
int x_;
RelocInfo::Mode rmode_;
friend class Assembler;
};
// -----------------------------------------------------------------------------
// Machine instruction Operands
enum ScaleFactor {
times_1 = 0,
times_2 = 1,
times_4 = 2,
times_8 = 3
};
class Operand BASE_EMBEDDED {
public:
// reg
INLINE(explicit Operand(Register reg));
// [disp/r]
INLINE(explicit Operand(int32_t disp, RelocInfo::Mode rmode));
// disp only must always be relocated
// [base + disp/r]
explicit Operand(Register base, int32_t disp,
RelocInfo::Mode rmode = RelocInfo::NONE);
// [base + index*scale + disp/r]
explicit Operand(Register base,
Register index,
ScaleFactor scale,
int32_t disp,
RelocInfo::Mode rmode = RelocInfo::NONE);
// [index*scale + disp/r]
explicit Operand(Register index,
ScaleFactor scale,
int32_t disp,
RelocInfo::Mode rmode = RelocInfo::NONE);
static Operand StaticVariable(const ExternalReference& ext) {
return Operand(reinterpret_cast<int32_t>(ext.address()),
RelocInfo::EXTERNAL_REFERENCE);
}
static Operand StaticArray(Register index,
ScaleFactor scale,
const ExternalReference& arr) {
return Operand(index, scale, reinterpret_cast<int32_t>(arr.address()),
RelocInfo::EXTERNAL_REFERENCE);
}
// Returns true if this Operand is a wrapper for the specified register.
bool is_reg(Register reg) const;
private:
// Mutable because reg in ModR/M byte is set by Assembler via set_reg().
mutable byte buf_[6];
// The number of bytes in buf_.
unsigned int len_;
// Only valid if len_ > 4.
RelocInfo::Mode rmode_;
inline void set_modrm(int mod, // reg == 0
Register rm);
inline void set_sib(ScaleFactor scale, Register index, Register base);
inline void set_disp8(int8_t disp);
inline void set_dispr(int32_t disp, RelocInfo::Mode rmode);
inline void set_reg(Register reg) const;
friend class Assembler;
};
// -----------------------------------------------------------------------------
// A Displacement describes the 32bit immediate field of an instruction which
// may be used together with a Label in order to refer to a yet unknown code
// position. Displacements stored in the instruction stream are used to describe
// the instruction and to chain a list of instructions using the same Label.
// A Displacement contains 2 different fields:
//
// next field: position of next displacement in the chain (0 = end of list)
// type field: instruction type
//
// A next value of null (0) indicates the end of a chain (note that there can
// be no displacement at position zero, because there is always at least one
// instruction byte before the displacement).
//
// Displacement _data field layout
//
// |31.....1| ......0|
// [ next | type |
class Displacement BASE_EMBEDDED {
public:
enum Type {
UNCONDITIONAL_JUMP,
OTHER
};
int data() const { return data_; }
Type type() const { return TypeField::decode(data_); }
void next(Label* L) const {
int n = NextField::decode(data_);
n > 0 ? L->link_to(n) : L->Unuse();
}
void link_to(Label* L) { init(L, type()); }
explicit Displacement(int data) { data_ = data; }
Displacement(Label* L, Type type) { init(L, type); }
void print() {
PrintF("%s (%x) ", (type() == UNCONDITIONAL_JUMP ? "jmp" : "[other]"),
NextField::decode(data_));
}
private:
int data_;
class TypeField: public BitField<Type, 0, 1> {};
class NextField: public BitField<int, 1, 32-1> {};
void init(Label* L, Type type);
};
// CpuFeatures keeps track of which features are supported by the target CPU.
// Supported features must be enabled by a Scope before use.
// Example:
// if (CpuFeatures::IsSupported(SSE2)) {
// CpuFeatures::Scope fscope(SSE2);
// // Generate SSE2 floating point code.
// } else {
// // Generate standard x87 floating point code.
// }
class CpuFeatures : public AllStatic {
public:
// Feature flags bit positions. They are mostly based on the CPUID spec.
// (We assign CPUID itself to one of the currently reserved bits --
// feel free to change this if needed.)
enum Feature { SSE2 = 26, CMOV = 15, RDTSC = 4, CPUID = 10 };
// Detect features of the target CPU. Set safe defaults if the serializer
// is enabled (snapshots must be portable).
static void Probe();
// Check whether a feature is supported by the target CPU.
static bool IsSupported(Feature f) { return supported_ & (1 << f); }
// Check whether a feature is currently enabled.
static bool IsEnabled(Feature f) { return enabled_ & (1 << f); }
// Enable a specified feature within a scope.
class Scope BASE_EMBEDDED {
#ifdef DEBUG
public:
explicit Scope(Feature f) {
ASSERT(CpuFeatures::IsSupported(f));
old_enabled_ = CpuFeatures::enabled_;
CpuFeatures::enabled_ |= (1 << f);
}
~Scope() { CpuFeatures::enabled_ = old_enabled_; }
private:
uint32_t old_enabled_;
#else
public:
explicit Scope(Feature f) {}
#endif
};
private:
static uint32_t supported_;
static uint32_t enabled_;
};
class Assembler : public Malloced {
private:
// The relocation writer's position is kGap bytes below the end of
// the generated instructions. This leaves enough space for the
// longest possible ia32 instruction (17 bytes as of 9/26/06) and
// allows for a single, fast space check per instruction.
static const int kGap = 32;
public:
// Create an assembler. Instructions and relocation information are emitted
// into a buffer, with the instructions starting from the beginning and the
// relocation information starting from the end of the buffer. See CodeDesc
// for a detailed comment on the layout (globals.h).
//
// If the provided buffer is NULL, the assembler allocates and grows its own
// buffer, and buffer_size determines the initial buffer size. The buffer is
// owned by the assembler and deallocated upon destruction of the assembler.
//
// If the provided buffer is not NULL, the assembler uses the provided buffer
// for code generation and assumes its size to be buffer_size. If the buffer
// is too small, a fatal error occurs. No deallocation of the buffer is done
// upon destruction of the assembler.
Assembler(void* buffer, int buffer_size);
~Assembler();
// GetCode emits any pending (non-emitted) code and fills the descriptor
// desc. GetCode() is idempotent; it returns the same result if no other
// Assembler functions are invoked inbetween GetCode() calls.
void GetCode(CodeDesc* desc);
// Read/Modify the code target in the branch/call instruction at pc.
inline static Address target_address_at(Address pc);
inline static void set_target_address_at(Address pc, Address target);
// Distance between the address of the code target in the call instruction
// and the return address
static const int kTargetAddrToReturnAddrDist = kPointerSize;
// ---------------------------------------------------------------------------
// Code generation
//
// - function names correspond one-to-one to ia32 instruction mnemonics
// - unless specified otherwise, instructions operate on 32bit operands
// - instructions on 8bit (byte) operands/registers have a trailing '_b'
// - instructions on 16bit (word) operands/registers have a trailing '_w'
// - naming conflicts with C++ keywords are resolved via a trailing '_'
// NOTE ON INTERFACE: Currently, the interface is not very consistent
// in the sense that some operations (e.g. mov()) can be called in more
// the one way to generate the same instruction: The Register argument
// can in some cases be replaced with an Operand(Register) argument.
// This should be cleaned up and made more othogonal. The questions
// is: should we always use Operands instead of Registers where an
// Operand is possible, or should we have a Register (overloaded) form
// instead? We must be carefull to make sure that the selected instruction
// is obvious from the parameters to avoid hard-to-find code generation
// bugs.
// Insert the smallest number of nop instructions
// possible to align the pc offset to a multiple
// of m. m must be a power of 2.
void Align(int m);
// Stack
void pushad();
void popad();
void pushfd();
void popfd();
void push(const Immediate& x);
void push(Register src);
void push(const Operand& src);
void pop(Register dst);
void pop(const Operand& dst);
// Moves
void mov_b(Register dst, const Operand& src);
void mov_b(const Operand& dst, int8_t imm8);
void mov_b(const Operand& dst, Register src);
void mov_w(Register dst, const Operand& src);
void mov_w(const Operand& dst, Register src);
void mov(Register dst, int32_t imm32);
void mov(Register dst, Handle<Object> handle);
void mov(Register dst, const Operand& src);
void mov(const Operand& dst, const Immediate& x);
void mov(const Operand& dst, Handle<Object> handle);
void mov(const Operand& dst, Register src);
void movsx_b(Register dst, const Operand& src);
void movsx_w(Register dst, const Operand& src);
void movzx_b(Register dst, const Operand& src);
void movzx_w(Register dst, const Operand& src);
// Conditional moves
void cmov(Condition cc, Register dst, int32_t imm32);
void cmov(Condition cc, Register dst, Handle<Object> handle);
void cmov(Condition cc, Register dst, const Operand& src);
// Arithmetics
void adc(Register dst, int32_t imm32);
void adc(Register dst, const Operand& src);
void add(Register dst, const Operand& src);
void add(const Operand& dst, const Immediate& x);
void and_(Register dst, int32_t imm32);
void and_(Register dst, const Operand& src);
void and_(const Operand& src, Register dst);
void and_(const Operand& dst, const Immediate& x);
void cmp(Register reg, int32_t imm32);
void cmp(Register reg, Handle<Object> handle);
void cmp(Register reg, const Operand& op);
void cmp(const Operand& op, const Immediate& imm);
void dec_b(Register dst);
void dec(Register dst);
void dec(const Operand& dst);
void cdq();
void idiv(Register src);
void imul(Register dst, const Operand& src);
void imul(Register dst, Register src, int32_t imm32);
void inc(Register dst);
void inc(const Operand& dst);
void lea(Register dst, const Operand& src);
void mul(Register src);
void neg(Register dst);
void not_(Register dst);
void or_(Register dst, int32_t imm32);
void or_(Register dst, const Operand& src);
void or_(const Operand& dst, Register src);
void or_(const Operand& dst, const Immediate& x);
void rcl(Register dst, uint8_t imm8);
void sar(Register dst, uint8_t imm8);
void sar(Register dst);
void sbb(Register dst, const Operand& src);
void shld(Register dst, const Operand& src);
void shl(Register dst, uint8_t imm8);
void shl(Register dst);
void shrd(Register dst, const Operand& src);
void shr(Register dst, uint8_t imm8);
void shr(Register dst);
void sub(const Operand& dst, const Immediate& x);
void sub(Register dst, const Operand& src);
void sub(const Operand& dst, Register src);
void test(Register reg, const Immediate& imm);
void test(Register reg, const Operand& op);
void test(const Operand& op, const Immediate& imm);
void xor_(Register dst, int32_t imm32);
void xor_(Register dst, const Operand& src);
void xor_(const Operand& src, Register dst);
void xor_(const Operand& dst, const Immediate& x);
// Bit operations.
void bts(const Operand& dst, Register src);
// Miscellaneous
void hlt();
void int3();
void nop();
void rdtsc();
void ret(int imm16);
void leave();
// Label operations & relative jumps (PPUM Appendix D)
//
// Takes a branch opcode (cc) and a label (L) and generates
// either a backward branch or a forward branch and links it
// to the label fixup chain. Usage:
//
// Label L; // unbound label
// j(cc, &L); // forward branch to unbound label
// bind(&L); // bind label to the current pc
// j(cc, &L); // backward branch to bound label
// bind(&L); // illegal: a label may be bound only once
//
// Note: The same Label can be used for forward and backward branches
// but it may be bound only once.
void bind(Label* L); // binds an unbound label L to the current code position
// Calls
void call(Label* L);
void call(byte* entry, RelocInfo::Mode rmode);
void call(const Operand& adr);
void call(Handle<Code> code, RelocInfo::Mode rmode);
// Jumps
void jmp(Label* L); // unconditional jump to L
void jmp(byte* entry, RelocInfo::Mode rmode);
void jmp(const Operand& adr);
void jmp(Handle<Code> code, RelocInfo::Mode rmode);
// Conditional jumps
void j(Condition cc, Label* L, Hint hint = no_hint);
void j(Condition cc, byte* entry, RelocInfo::Mode rmode, Hint hint = no_hint);
void j(Condition cc, Handle<Code> code, Hint hint = no_hint);
// Floating-point operations
void fld(int i);
void fld1();
void fldz();
void fld_s(const Operand& adr);
void fld_d(const Operand& adr);
void fstp_s(const Operand& adr);
void fstp_d(const Operand& adr);
void fild_s(const Operand& adr);
void fild_d(const Operand& adr);
void fist_s(const Operand& adr);
void fistp_s(const Operand& adr);
void fistp_d(const Operand& adr);
void fabs();
void fchs();
void fadd(int i);
void fsub(int i);
void fmul(int i);
void fdiv(int i);
void fisub_s(const Operand& adr);
void faddp(int i = 1);
void fsubp(int i = 1);
void fsubrp(int i = 1);
void fmulp(int i = 1);
void fdivp(int i = 1);
void fprem();
void fprem1();
void fxch(int i = 1);
void fincstp();
void ffree(int i = 0);
void ftst();
void fucomp(int i);
void fucompp();
void fcompp();
void fnstsw_ax();
void fwait();
void frndint();
void sahf();
void cpuid();
// SSE2 instructions
void cvttss2si(Register dst, const Operand& src);
void cvttsd2si(Register dst, const Operand& src);
void cvtsi2sd(XMMRegister dst, const Operand& src);
void addsd(XMMRegister dst, XMMRegister src);
void subsd(XMMRegister dst, XMMRegister src);
void mulsd(XMMRegister dst, XMMRegister src);
void divsd(XMMRegister dst, XMMRegister src);
// Use either movsd or movlpd.
void movdbl(XMMRegister dst, const Operand& src);
void movdbl(const Operand& dst, XMMRegister src);
// Debugging
void Print();
// Check the code size generated from label to here.
int SizeOfCodeGeneratedSince(Label* l) { return pc_offset() - l->pos(); }
// Mark address of the ExitJSFrame code.
void RecordJSReturn();
// Record a comment relocation entry that can be used by a disassembler.
// Use --debug_code to enable.
void RecordComment(const char* msg);
void RecordPosition(int pos);
void RecordStatementPosition(int pos);
void WriteRecordedPositions();
// Writes a single word of data in the code stream.
// Used for inline tables, e.g., jump-tables.
void dd(uint32_t data, RelocInfo::Mode reloc_info);
// Writes the absolute address of a bound label at the given position in
// the generated code. That positions should have the relocation mode
// internal_reference!
void WriteInternalReference(int position, const Label& bound_label);
int pc_offset() const { return pc_ - buffer_; }
int last_statement_position() const { return last_statement_position_; }
int last_position() const { return last_position_; }
// Check if there is less than kGap bytes available in the buffer.
// If this is the case, we need to grow the buffer before emitting
// an instruction or relocation information.
inline bool overflow() const { return pc_ >= reloc_info_writer.pos() - kGap; }
// Get the number of bytes available in the buffer.
inline int available_space() const { return reloc_info_writer.pos() - pc_; }
// Avoid overflows for displacements etc.
static const int kMaximalBufferSize = 512*MB;
static const int kMinimalBufferSize = 4*KB;
protected:
void movsd(XMMRegister dst, const Operand& src);
void movsd(const Operand& dst, XMMRegister src);
void emit_sse_operand(XMMRegister reg, const Operand& adr);
void emit_sse_operand(XMMRegister dst, XMMRegister src);
private:
// Code buffer:
// The buffer into which code and relocation info are generated.
byte* buffer_;
int buffer_size_;
// True if the assembler owns the buffer, false if buffer is external.
bool own_buffer_;
// code generation
byte* pc_; // the program counter; moves forward
RelocInfoWriter reloc_info_writer;
// push-pop elimination
byte* last_pc_;
// source position information
int last_position_;
int last_statement_position_;
byte* addr_at(int pos) { return buffer_ + pos; }
byte byte_at(int pos) { return buffer_[pos]; }
uint32_t long_at(int pos) {
return *reinterpret_cast<uint32_t*>(addr_at(pos));
}
void long_at_put(int pos, uint32_t x) {
*reinterpret_cast<uint32_t*>(addr_at(pos)) = x;
}
// code emission
void GrowBuffer();
inline void emit(uint32_t x);
inline void emit(Handle<Object> handle);
inline void emit(uint32_t x, RelocInfo::Mode rmode);
inline void emit(const Immediate& x);
// instruction generation
void emit_arith_b(int op1, int op2, Register dst, int imm8);
// Emit a basic arithmetic instruction (i.e. first byte of the family is 0x81)
// with a given destination expression and an immediate operand. It attempts
// to use the shortest encoding possible.
// sel specifies the /n in the modrm byte (see the Intel PRM).
void emit_arith(int sel, Operand dst, const Immediate& x);
void emit_operand(Register reg, const Operand& adr);
void emit_operand(const Operand& adr, Register reg);
void emit_farith(int b1, int b2, int i);
// labels
void print(Label* L);
void bind_to(Label* L, int pos);
void link_to(Label* L, Label* appendix);
// displacements
inline Displacement disp_at(Label* L);
inline void disp_at_put(Label* L, Displacement disp);
inline void emit_disp(Label* L, Displacement::Type type);
// record reloc info for current pc_
void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
friend class CodePatcher;
friend class EnsureSpace;
};
// Helper class that ensures that there is enough space for generating
// instructions and relocation information. The constructor makes
// sure that there is enough space and (in debug mode) the destructor
// checks that we did not generate too much.
class EnsureSpace BASE_EMBEDDED {
public:
explicit EnsureSpace(Assembler* assembler) : assembler_(assembler) {
if (assembler_->overflow()) assembler_->GrowBuffer();
#ifdef DEBUG
space_before_ = assembler_->available_space();
#endif
}
#ifdef DEBUG
~EnsureSpace() {
int bytes_generated = space_before_ - assembler_->available_space();
ASSERT(bytes_generated < assembler_->kGap);
}
#endif
private:
Assembler* assembler_;
#ifdef DEBUG
int space_before_;
#endif
};
} } // namespace v8::internal
#endif // V8_ASSEMBLER_IA32_H_

View File

@ -1,575 +0,0 @@
// Copyright (c) 1994-2006 Sun Microsystems Inc.
// All Rights Reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// - Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// - Redistribution 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 Sun Microsystems or the names of contributors may
// be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// The original source code covered by the above license above has been
// modified significantly by Google Inc.
// Copyright 2006-2008 the V8 project authors. All rights reserved.
#include "v8.h"
#include "arguments.h"
#include "execution.h"
#include "ic-inl.h"
#include "factory.h"
#include "runtime.h"
#include "serialize.h"
#include "stub-cache.h"
namespace v8 { namespace internal {
// -----------------------------------------------------------------------------
// Implementation of Label
int Label::pos() const {
if (pos_ < 0) return -pos_ - 1;
if (pos_ > 0) return pos_ - 1;
UNREACHABLE();
return 0;
}
// -----------------------------------------------------------------------------
// Implementation of RelocInfoWriter and RelocIterator
//
// Encoding
//
// The most common modes are given single-byte encodings. Also, it is
// easy to identify the type of reloc info and skip unwanted modes in
// an iteration.
//
// The encoding relies on the fact that there are less than 14
// different relocation modes.
//
// embedded_object: [6 bits pc delta] 00
//
// code_taget: [6 bits pc delta] 01
//
// position: [6 bits pc delta] 10,
// [7 bits signed data delta] 0
//
// statement_position: [6 bits pc delta] 10,
// [7 bits signed data delta] 1
//
// any nondata mode: 00 [4 bits rmode] 11, // rmode: 0..13 only
// 00 [6 bits pc delta]
//
// pc-jump: 00 1111 11,
// 00 [6 bits pc delta]
//
// pc-jump: 01 1111 11,
// (variable length) 7 - 26 bit pc delta, written in chunks of 7
// bits, the lowest 7 bits written first.
//
// data-jump + pos: 00 1110 11,
// signed int, lowest byte written first
//
// data-jump + st.pos: 01 1110 11,
// signed int, lowest byte written first
//
// data-jump + comm.: 10 1110 11,
// signed int, lowest byte written first
//
const int kMaxRelocModes = 14;
const int kTagBits = 2;
const int kTagMask = (1 << kTagBits) - 1;
const int kExtraTagBits = 4;
const int kPositionTypeTagBits = 1;
const int kSmallDataBits = kBitsPerByte - kPositionTypeTagBits;
const int kEmbeddedObjectTag = 0;
const int kCodeTargetTag = 1;
const int kPositionTag = 2;
const int kDefaultTag = 3;
const int kPCJumpTag = (1 << kExtraTagBits) - 1;
const int kSmallPCDeltaBits = kBitsPerByte - kTagBits;
const int kSmallPCDeltaMask = (1 << kSmallPCDeltaBits) - 1;
const int kVariableLengthPCJumpTopTag = 1;
const int kChunkBits = 7;
const int kChunkMask = (1 << kChunkBits) - 1;
const int kLastChunkTagBits = 1;
const int kLastChunkTagMask = 1;
const int kLastChunkTag = 1;
const int kDataJumpTag = kPCJumpTag - 1;
const int kNonstatementPositionTag = 0;
const int kStatementPositionTag = 1;
const int kCommentTag = 2;
uint32_t RelocInfoWriter::WriteVariableLengthPCJump(uint32_t pc_delta) {
// Return if the pc_delta can fit in kSmallPCDeltaBits bits.
// Otherwise write a variable length PC jump for the bits that do
// not fit in the kSmallPCDeltaBits bits.
if (is_uintn(pc_delta, kSmallPCDeltaBits)) return pc_delta;
WriteExtraTag(kPCJumpTag, kVariableLengthPCJumpTopTag);
uint32_t pc_jump = pc_delta >> kSmallPCDeltaBits;
ASSERT(pc_jump > 0);
// Write kChunkBits size chunks of the pc_jump.
for (; pc_jump > 0; pc_jump = pc_jump >> kChunkBits) {
byte b = pc_jump & kChunkMask;
*--pos_ = b << kLastChunkTagBits;
}
// Tag the last chunk so it can be identified.
*pos_ = *pos_ | kLastChunkTag;
// Return the remaining kSmallPCDeltaBits of the pc_delta.
return pc_delta & kSmallPCDeltaMask;
}
void RelocInfoWriter::WriteTaggedPC(uint32_t pc_delta, int tag) {
// Write a byte of tagged pc-delta, possibly preceded by var. length pc-jump.
pc_delta = WriteVariableLengthPCJump(pc_delta);
*--pos_ = pc_delta << kTagBits | tag;
}
void RelocInfoWriter::WriteTaggedData(int32_t data_delta, int tag) {
*--pos_ = data_delta << kPositionTypeTagBits | tag;
}
void RelocInfoWriter::WriteExtraTag(int extra_tag, int top_tag) {
*--pos_ = top_tag << (kTagBits + kExtraTagBits) |
extra_tag << kTagBits |
kDefaultTag;
}
void RelocInfoWriter::WriteExtraTaggedPC(uint32_t pc_delta, int extra_tag) {
// Write two-byte tagged pc-delta, possibly preceded by var. length pc-jump.
pc_delta = WriteVariableLengthPCJump(pc_delta);
WriteExtraTag(extra_tag, 0);
*--pos_ = pc_delta;
}
void RelocInfoWriter::WriteExtraTaggedData(int32_t data_delta, int top_tag) {
WriteExtraTag(kDataJumpTag, top_tag);
for (int i = 0; i < kIntSize; i++) {
*--pos_ = data_delta;
data_delta = ArithmeticShiftRight(data_delta, kBitsPerByte);
}
}
void RelocInfoWriter::Write(const RelocInfo* rinfo) {
#ifdef DEBUG
byte* begin_pos = pos_;
#endif
Counters::reloc_info_count.Increment();
ASSERT(rinfo->pc() - last_pc_ >= 0);
ASSERT(RelocInfo::NUMBER_OF_MODES < kMaxRelocModes);
// Use unsigned delta-encoding for pc.
uint32_t pc_delta = rinfo->pc() - last_pc_;
RelocInfo::Mode rmode = rinfo->rmode();
// The two most common modes are given small tags, and usually fit in a byte.
if (rmode == RelocInfo::EMBEDDED_OBJECT) {
WriteTaggedPC(pc_delta, kEmbeddedObjectTag);
} else if (rmode == RelocInfo::CODE_TARGET) {
WriteTaggedPC(pc_delta, kCodeTargetTag);
} else if (RelocInfo::IsPosition(rmode)) {
// Use signed delta-encoding for data.
int32_t data_delta = rinfo->data() - last_data_;
int pos_type_tag = rmode == RelocInfo::POSITION ? kNonstatementPositionTag
: kStatementPositionTag;
// Check if data is small enough to fit in a tagged byte.
if (is_intn(data_delta, kSmallDataBits)) {
WriteTaggedPC(pc_delta, kPositionTag);
WriteTaggedData(data_delta, pos_type_tag);
last_data_ = rinfo->data();
} else {
// Otherwise, use costly encoding.
WriteExtraTaggedPC(pc_delta, kPCJumpTag);
WriteExtraTaggedData(data_delta, pos_type_tag);
last_data_ = rinfo->data();
}
} else if (RelocInfo::IsComment(rmode)) {
// Comments are normally not generated, so we use the costly encoding.
WriteExtraTaggedPC(pc_delta, kPCJumpTag);
WriteExtraTaggedData(rinfo->data() - last_data_, kCommentTag);
last_data_ = rinfo->data();
} else {
// For all other modes we simply use the mode as the extra tag.
// None of these modes need a data component.
ASSERT(rmode < kPCJumpTag && rmode < kDataJumpTag);
WriteExtraTaggedPC(pc_delta, rmode);
}
last_pc_ = rinfo->pc();
#ifdef DEBUG
ASSERT(begin_pos - pos_ <= kMaxSize);
#endif
}
inline int RelocIterator::AdvanceGetTag() {
return *--pos_ & kTagMask;
}
inline int RelocIterator::GetExtraTag() {
return (*pos_ >> kTagBits) & ((1 << kExtraTagBits) - 1);
}
inline int RelocIterator::GetTopTag() {
return *pos_ >> (kTagBits + kExtraTagBits);
}
inline void RelocIterator::ReadTaggedPC() {
rinfo_.pc_ += *pos_ >> kTagBits;
}
inline void RelocIterator::AdvanceReadPC() {
rinfo_.pc_ += *--pos_;
}
void RelocIterator::AdvanceReadData() {
int32_t x = 0;
for (int i = 0; i < kIntSize; i++) {
x |= *--pos_ << i * kBitsPerByte;
}
rinfo_.data_ += x;
}
void RelocIterator::AdvanceReadVariableLengthPCJump() {
// Read the 32-kSmallPCDeltaBits most significant bits of the
// pc jump in kChunkBits bit chunks and shift them into place.
// Stop when the last chunk is encountered.
uint32_t pc_jump = 0;
for (int i = 0; i < kIntSize; i++) {
byte pc_jump_part = *--pos_;
pc_jump |= (pc_jump_part >> kLastChunkTagBits) << i * kChunkBits;
if ((pc_jump_part & kLastChunkTagMask) == 1) break;
}
// The least significant kSmallPCDeltaBits bits will be added
// later.
rinfo_.pc_ += pc_jump << kSmallPCDeltaBits;
}
inline int RelocIterator::GetPositionTypeTag() {
return *pos_ & ((1 << kPositionTypeTagBits) - 1);
}
inline void RelocIterator::ReadTaggedData() {
int8_t signed_b = *pos_;
rinfo_.data_ += ArithmeticShiftRight(signed_b, kPositionTypeTagBits);
}
inline RelocInfo::Mode RelocIterator::DebugInfoModeFromTag(int tag) {
if (tag == kStatementPositionTag) {
return RelocInfo::STATEMENT_POSITION;
} else if (tag == kNonstatementPositionTag) {
return RelocInfo::POSITION;
} else {
ASSERT(tag == kCommentTag);
return RelocInfo::COMMENT;
}
}
void RelocIterator::next() {
ASSERT(!done());
// Basically, do the opposite of RelocInfoWriter::Write.
// Reading of data is as far as possible avoided for unwanted modes,
// but we must always update the pc.
//
// We exit this loop by returning when we find a mode we want.
while (pos_ > end_) {
int tag = AdvanceGetTag();
if (tag == kEmbeddedObjectTag) {
ReadTaggedPC();
if (SetMode(RelocInfo::EMBEDDED_OBJECT)) return;
} else if (tag == kCodeTargetTag) {
ReadTaggedPC();
if (*(reinterpret_cast<int*>(rinfo_.pc())) == 0x61) {
tag = 0;
}
if (SetMode(RelocInfo::CODE_TARGET)) return;
} else if (tag == kPositionTag) {
ReadTaggedPC();
Advance();
// Check if we want source positions.
if (mode_mask_ & RelocInfo::kPositionMask) {
// Check if we want this type of source position.
if (SetMode(DebugInfoModeFromTag(GetPositionTypeTag()))) {
// Finally read the data before returning.
ReadTaggedData();
return;
}
}
} else {
ASSERT(tag == kDefaultTag);
int extra_tag = GetExtraTag();
if (extra_tag == kPCJumpTag) {
int top_tag = GetTopTag();
if (top_tag == kVariableLengthPCJumpTopTag) {
AdvanceReadVariableLengthPCJump();
} else {
AdvanceReadPC();
}
} else if (extra_tag == kDataJumpTag) {
// Check if we want debug modes (the only ones with data).
if (mode_mask_ & RelocInfo::kDebugMask) {
int top_tag = GetTopTag();
AdvanceReadData();
if (SetMode(DebugInfoModeFromTag(top_tag))) return;
} else {
// Otherwise, just skip over the data.
Advance(kIntSize);
}
} else {
AdvanceReadPC();
if (SetMode(static_cast<RelocInfo::Mode>(extra_tag))) return;
}
}
}
done_ = true;
}
RelocIterator::RelocIterator(Code* code, int mode_mask) {
rinfo_.pc_ = code->instruction_start();
rinfo_.data_ = 0;
// relocation info is read backwards
pos_ = code->relocation_start() + code->relocation_size();
end_ = code->relocation_start();
done_ = false;
mode_mask_ = mode_mask;
if (mode_mask_ == 0) pos_ = end_;
next();
}
RelocIterator::RelocIterator(const CodeDesc& desc, int mode_mask) {
rinfo_.pc_ = desc.buffer;
rinfo_.data_ = 0;
// relocation info is read backwards
pos_ = desc.buffer + desc.buffer_size;
end_ = pos_ - desc.reloc_size;
done_ = false;
mode_mask_ = mode_mask;
if (mode_mask_ == 0) pos_ = end_;
next();
}
// -----------------------------------------------------------------------------
// Implementation of RelocInfo
#ifdef ENABLE_DISASSEMBLER
const char* RelocInfo::RelocModeName(RelocInfo::Mode rmode) {
switch (rmode) {
case RelocInfo::NONE:
return "no reloc";
case RelocInfo::EMBEDDED_OBJECT:
return "embedded object";
case RelocInfo::EMBEDDED_STRING:
return "embedded string";
case RelocInfo::CONSTRUCT_CALL:
return "code target (js construct call)";
case RelocInfo::CODE_TARGET_CONTEXT:
return "code target (context)";
case RelocInfo::CODE_TARGET:
return "code target";
case RelocInfo::RUNTIME_ENTRY:
return "runtime entry";
case RelocInfo::JS_RETURN:
return "js return";
case RelocInfo::COMMENT:
return "comment";
case RelocInfo::POSITION:
return "position";
case RelocInfo::STATEMENT_POSITION:
return "statement position";
case RelocInfo::EXTERNAL_REFERENCE:
return "external reference";
case RelocInfo::INTERNAL_REFERENCE:
return "internal reference";
case RelocInfo::NUMBER_OF_MODES:
UNREACHABLE();
return "number_of_modes";
}
return "unknown relocation type";
}
void RelocInfo::Print() {
PrintF("%p %s", pc_, RelocModeName(rmode_));
if (IsComment(rmode_)) {
PrintF(" (%s)", data_);
} else if (rmode_ == EMBEDDED_OBJECT) {
PrintF(" (");
target_object()->ShortPrint();
PrintF(")");
} else if (rmode_ == EXTERNAL_REFERENCE) {
ExternalReferenceEncoder ref_encoder;
PrintF(" (%s) (%p)",
ref_encoder.NameOfAddress(*target_reference_address()),
*target_reference_address());
} else if (IsCodeTarget(rmode_)) {
Code* code = Debug::GetCodeTarget(target_address());
PrintF(" (%s) (%p)", Code::Kind2String(code->kind()), target_address());
} else if (IsPosition(rmode_)) {
PrintF(" (%d)", data());
}
PrintF("\n");
}
#endif // ENABLE_DISASSEMBLER
#ifdef DEBUG
void RelocInfo::Verify() {
switch (rmode_) {
case EMBEDDED_OBJECT:
Object::VerifyPointer(target_object());
break;
case CONSTRUCT_CALL:
case CODE_TARGET_CONTEXT:
case CODE_TARGET: {
// convert inline target address to code object
Address addr = target_address();
ASSERT(addr != NULL);
// Check that we can find the right code object.
HeapObject* code = HeapObject::FromAddress(addr - Code::kHeaderSize);
Object* found = Heap::FindCodeObject(addr);
ASSERT(found->IsCode());
ASSERT(code->address() == HeapObject::cast(found)->address());
break;
}
case RelocInfo::EMBEDDED_STRING:
case RUNTIME_ENTRY:
case JS_RETURN:
case COMMENT:
case POSITION:
case STATEMENT_POSITION:
case EXTERNAL_REFERENCE:
case INTERNAL_REFERENCE:
case NONE:
break;
case NUMBER_OF_MODES:
UNREACHABLE();
break;
}
}
#endif // DEBUG
// -----------------------------------------------------------------------------
// Implementation of ExternalReference
ExternalReference::ExternalReference(Builtins::CFunctionId id)
: address_(Builtins::c_function_address(id)) {}
ExternalReference::ExternalReference(Builtins::Name name)
: address_(Builtins::builtin_address(name)) {}
ExternalReference::ExternalReference(Runtime::FunctionId id)
: address_(Runtime::FunctionForId(id)->entry) {}
ExternalReference::ExternalReference(Runtime::Function* f)
: address_(f->entry) {}
ExternalReference::ExternalReference(const IC_Utility& ic_utility)
: address_(ic_utility.address()) {}
ExternalReference::ExternalReference(const Debug_Address& debug_address)
: address_(debug_address.address()) {}
ExternalReference::ExternalReference(StatsCounter* counter)
: address_(reinterpret_cast<Address>(counter->GetInternalPointer())) {}
ExternalReference::ExternalReference(Top::AddressId id)
: address_(Top::get_address_from_id(id)) {}
ExternalReference::ExternalReference(const SCTableReference& table_ref)
: address_(table_ref.address()) {}
ExternalReference ExternalReference::builtin_passed_function() {
return ExternalReference(&Builtins::builtin_passed_function);
}
ExternalReference ExternalReference::the_hole_value_location() {
return ExternalReference(Factory::the_hole_value().location());
}
ExternalReference ExternalReference::address_of_stack_guard_limit() {
return ExternalReference(StackGuard::address_of_jslimit());
}
ExternalReference ExternalReference::debug_break() {
return ExternalReference(FUNCTION_ADDR(Debug::Break));
}
ExternalReference ExternalReference::new_space_start() {
return ExternalReference(Heap::NewSpaceStart());
}
ExternalReference ExternalReference::new_space_allocation_top_address() {
return ExternalReference(Heap::NewSpaceAllocationTopAddress());
}
ExternalReference ExternalReference::new_space_allocation_limit_address() {
return ExternalReference(Heap::NewSpaceAllocationLimitAddress());
}
ExternalReference ExternalReference::debug_step_in_fp_address() {
return ExternalReference(Debug::step_in_fp_addr());
}
} } // namespace v8::internal

View File

@ -1,476 +0,0 @@
// Copyright (c) 1994-2006 Sun Microsystems Inc.
// All Rights Reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// - Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// - Redistribution 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 Sun Microsystems or the names of contributors may
// be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// The original source code covered by the above license above has been
// modified significantly by Google Inc.
// Copyright 2006-2008 the V8 project authors. All rights reserved.
#ifndef V8_ASSEMBLER_H_
#define V8_ASSEMBLER_H_
#include "runtime.h"
#include "top.h"
#include "zone-inl.h"
namespace v8 { namespace internal {
// -----------------------------------------------------------------------------
// Labels represent pc locations; they are typically jump or call targets.
// After declaration, a label can be freely used to denote known or (yet)
// unknown pc location. Assembler::bind() is used to bind a label to the
// current pc. A label can be bound only once.
class Label : public ZoneObject { // LabelShadows are dynamically allocated.
public:
INLINE(Label()) { Unuse(); }
INLINE(~Label()) { ASSERT(!is_linked()); }
INLINE(void Unuse()) { pos_ = 0; }
INLINE(bool is_bound() const) { return pos_ < 0; }
INLINE(bool is_unused() const) { return pos_ == 0; }
INLINE(bool is_linked() const) { return pos_ > 0; }
// Returns the position of bound or linked labels. Cannot be used
// for unused labels.
int pos() const;
private:
// pos_ encodes both the binding state (via its sign)
// and the binding position (via its value) of a label.
//
// pos_ < 0 bound label, pos() returns the jump target position
// pos_ == 0 unused label
// pos_ > 0 linked label, pos() returns the last reference position
int pos_;
void bind_to(int pos) {
pos_ = -pos - 1;
ASSERT(is_bound());
}
void link_to(int pos) {
pos_ = pos + 1;
ASSERT(is_linked());
}
friend class Assembler;
friend class Displacement;
friend class LabelShadow;
};
// A LabelShadow represents a label that is temporarily shadowed by another
// label (represented by the original label during shadowing). They are used
// to catch jumps to labels in certain contexts, e.g. try blocks. After
// shadowing ends, the formerly shadowed label is again represented by the
// original label and the LabelShadow can be used as a label in its own
// right, representing the formerly shadowing label.
class LabelShadow : public Label {
public:
explicit LabelShadow(Label* original) {
ASSERT(original != NULL);
original_label_ = original;
original_pos_ = original->pos_;
original->Unuse();
#ifdef DEBUG
is_shadowing_ = true;
#endif
}
~LabelShadow() {
ASSERT(!is_shadowing_);
}
void StopShadowing() {
ASSERT(is_shadowing_ && is_unused());
pos_ = original_label_->pos_;
original_label_->pos_ = original_pos_;
#ifdef DEBUG
is_shadowing_ = false;
#endif
}
Label* original_label() const { return original_label_; }
private:
// During shadowing, the currently shadowing label. After shadowing, the
// label that was shadowed.
Label* original_label_;
// During shadowing, the saved state of the original label.
int original_pos_;
#ifdef DEBUG
bool is_shadowing_;
#endif
};
// -----------------------------------------------------------------------------
// Relocation information
// Relocation information consists of the address (pc) of the datum
// to which the relocation information applies, the relocation mode
// (rmode), and an optional data field. The relocation mode may be
// "descriptive" and not indicate a need for relocation, but simply
// describe a property of the datum. Such rmodes are useful for GC
// and nice disassembly output.
class RelocInfo BASE_EMBEDDED {
public:
// The constant kNoPosition is used with the collecting of source positions
// in the relocation information. Two types of source positions are collected
// "position" (RelocMode position) and "statement position" (RelocMode
// statement_position). The "position" is collected at places in the source
// code which are of interest when making stack traces to pin-point the source
// location of a stack frame as close as possible. The "statement position" is
// collected at the beginning at each statement, and is used to indicate
// possible break locations. kNoPosition is used to indicate an
// invalid/uninitialized position value.
static const int kNoPosition = -1;
enum Mode {
// Please note the order is important (see IsCodeTarget, IsGCRelocMode).
CONSTRUCT_CALL, // code target that is a call to a JavaScript constructor.
CODE_TARGET_CONTEXT, // code target used for contextual loads.
CODE_TARGET, // code target which is not any of the above.
EMBEDDED_OBJECT,
EMBEDDED_STRING,
// Everything after runtime_entry (inclusive) is not GC'ed.
RUNTIME_ENTRY,
JS_RETURN, // Marks start of the ExitJSFrame code.
COMMENT,
POSITION, // See comment for kNoPosition above.
STATEMENT_POSITION, // See comment for kNoPosition above.
EXTERNAL_REFERENCE, // The address of an external C++ function.
INTERNAL_REFERENCE, // An address inside the same function.
// add more as needed
// Pseudo-types
NUMBER_OF_MODES, // must be no greater than 14 - see RelocInfoWriter
NONE, // never recorded
LAST_CODE_ENUM = CODE_TARGET,
LAST_GCED_ENUM = EMBEDDED_STRING
};
RelocInfo() {}
RelocInfo(byte* pc, Mode rmode, intptr_t data)
: pc_(pc), rmode_(rmode), data_(data) {
}
static inline bool IsConstructCall(Mode mode) {
return mode == CONSTRUCT_CALL;
}
static inline bool IsCodeTarget(Mode mode) {
return mode <= LAST_CODE_ENUM;
}
// Is the relocation mode affected by GC?
static inline bool IsGCRelocMode(Mode mode) {
return mode <= LAST_GCED_ENUM;
}
static inline bool IsJSReturn(Mode mode) {
return mode == JS_RETURN;
}
static inline bool IsComment(Mode mode) {
return mode == COMMENT;
}
static inline bool IsPosition(Mode mode) {
return mode == POSITION || mode == STATEMENT_POSITION;
}
static inline bool IsStatementPosition(Mode mode) {
return mode == STATEMENT_POSITION;
}
static inline bool IsExternalReference(Mode mode) {
return mode == EXTERNAL_REFERENCE;
}
static inline bool IsInternalReference(Mode mode) {
return mode == INTERNAL_REFERENCE;
}
static inline int ModeMask(Mode mode) { return 1 << mode; }
// Accessors
byte* pc() const { return pc_; }
void set_pc(byte* pc) { pc_ = pc; }
Mode rmode() const { return rmode_; }
intptr_t data() const { return data_; }
// Apply a relocation by delta bytes
INLINE(void apply(int delta));
// Read/modify the code target in the branch/call instruction this relocation
// applies to; can only be called if IsCodeTarget(rmode_)
INLINE(Address target_address());
INLINE(void set_target_address(Address target));
INLINE(Object* target_object());
INLINE(Object** target_object_address());
INLINE(void set_target_object(Object* target));
// Read/modify the reference in the instruction this relocation
// applies to; can only be called if rmode_ is external_reference
INLINE(Address* target_reference_address());
// Read/modify the address of a call instruction. This is used to relocate
// the break points where straight-line code is patched with a call
// instruction.
INLINE(Address call_address());
INLINE(void set_call_address(Address target));
INLINE(Object* call_object());
INLINE(Object** call_object_address());
INLINE(void set_call_object(Object* target));
// Patch the code with some other code.
void patch_code(byte* instructions, int instruction_count);
// Patch the code with a call.
void patch_code_with_call(Address target, int guard_bytes);
INLINE(bool is_call_instruction());
#ifdef ENABLE_DISASSEMBLER
// Printing
static const char* RelocModeName(Mode rmode);
void Print();
#endif // ENABLE_DISASSEMBLER
#ifdef DEBUG
// Debugging
void Verify();
#endif
static const int kCodeTargetMask = (1 << (LAST_CODE_ENUM + 1)) - 1;
static const int kPositionMask = 1 << POSITION | 1 << STATEMENT_POSITION;
static const int kDebugMask = kPositionMask | 1 << COMMENT;
static const int kApplyMask; // Modes affected by apply. Depends on arch.
private:
// On ARM, note that pc_ is the address of the constant pool entry
// to be relocated and not the address of the instruction
// referencing the constant pool entry (except when rmode_ ==
// comment).
byte* pc_;
Mode rmode_;
intptr_t data_;
friend class RelocIterator;
};
// RelocInfoWriter serializes a stream of relocation info. It writes towards
// lower addresses.
class RelocInfoWriter BASE_EMBEDDED {
public:
RelocInfoWriter() : pos_(NULL), last_pc_(NULL), last_data_(0) {}
RelocInfoWriter(byte* pos, byte* pc) : pos_(pos), last_pc_(pc),
last_data_(0) {}
byte* pos() const { return pos_; }
byte* last_pc() const { return last_pc_; }
void Write(const RelocInfo* rinfo);
// Update the state of the stream after reloc info buffer
// and/or code is moved while the stream is active.
void Reposition(byte* pos, byte* pc) {
pos_ = pos;
last_pc_ = pc;
}
// Max size (bytes) of a written RelocInfo.
static const int kMaxSize = 12;
private:
inline uint32_t WriteVariableLengthPCJump(uint32_t pc_delta);
inline void WriteTaggedPC(uint32_t pc_delta, int tag);
inline void WriteExtraTaggedPC(uint32_t pc_delta, int extra_tag);
inline void WriteExtraTaggedData(int32_t data_delta, int top_tag);
inline void WriteTaggedData(int32_t data_delta, int tag);
inline void WriteExtraTag(int extra_tag, int top_tag);
byte* pos_;
byte* last_pc_;
intptr_t last_data_;
DISALLOW_COPY_AND_ASSIGN(RelocInfoWriter);
};
// A RelocIterator iterates over relocation information.
// Typical use:
//
// for (RelocIterator it(code); !it.done(); it.next()) {
// // do something with it.rinfo() here
// }
//
// A mask can be specified to skip unwanted modes.
class RelocIterator: public Malloced {
public:
// Create a new iterator positioned at
// the beginning of the reloc info.
// Relocation information with mode k is included in the
// iteration iff bit k of mode_mask is set.
explicit RelocIterator(Code* code, int mode_mask = -1);
explicit RelocIterator(const CodeDesc& desc, int mode_mask = -1);
// Iteration
bool done() const { return done_; }
void next();
// Return pointer valid until next next().
RelocInfo* rinfo() {
ASSERT(!done());
return &rinfo_;
}
private:
// Advance* moves the position before/after reading.
// *Read* reads from current byte(s) into rinfo_.
// *Get* just reads and returns info on current byte.
void Advance(int bytes = 1) { pos_ -= bytes; }
int AdvanceGetTag();
int GetExtraTag();
int GetTopTag();
void ReadTaggedPC();
void AdvanceReadPC();
void AdvanceReadData();
void AdvanceReadVariableLengthPCJump();
int GetPositionTypeTag();
void ReadTaggedData();
static RelocInfo::Mode DebugInfoModeFromTag(int tag);
// If the given mode is wanted, set it in rinfo_ and return true.
// Else return false. Used for efficiently skipping unwanted modes.
bool SetMode(RelocInfo::Mode mode) {
return (mode_mask_ & 1 << mode) ? (rinfo_.rmode_ = mode, true) : false;
}
byte* pos_;
byte* end_;
RelocInfo rinfo_;
bool done_;
int mode_mask_;
DISALLOW_COPY_AND_ASSIGN(RelocIterator);
};
//------------------------------------------------------------------------------
// External function
//----------------------------------------------------------------------------
class IC_Utility;
class Debug_Address;
class SCTableReference;
// An ExternalReference represents a C++ address called from the generated
// code. All references to C++ functions and must be encapsulated in an
// ExternalReference instance. This is done in order to track the origin of
// all external references in the code.
class ExternalReference BASE_EMBEDDED {
public:
explicit ExternalReference(Builtins::CFunctionId id);
explicit ExternalReference(Builtins::Name name);
explicit ExternalReference(Runtime::FunctionId id);
explicit ExternalReference(Runtime::Function* f);
explicit ExternalReference(const IC_Utility& ic_utility);
explicit ExternalReference(const Debug_Address& debug_address);
explicit ExternalReference(StatsCounter* counter);
explicit ExternalReference(Top::AddressId id);
explicit ExternalReference(const SCTableReference& table_ref);
// One-of-a-kind references. These references are not part of a general
// pattern. This means that they have to be added to the
// ExternalReferenceTable in serialize.cc manually.
static ExternalReference builtin_passed_function();
// Static variable Factory::the_hole_value.location()
static ExternalReference the_hole_value_location();
// Static variable StackGuard::address_of_limit()
static ExternalReference address_of_stack_guard_limit();
// Function Debug::Break()
static ExternalReference debug_break();
// Static variable Heap::NewSpaceStart()
static ExternalReference new_space_start();
// Used for fast allocation in generated code.
static ExternalReference new_space_allocation_top_address();
static ExternalReference new_space_allocation_limit_address();
// Used to check if single stepping is enabled in generated code.
static ExternalReference debug_step_in_fp_address();
Address address() const {return address_;}
private:
explicit ExternalReference(void* address)
: address_(reinterpret_cast<Address>(address)) {}
Address address_;
};
// -----------------------------------------------------------------------------
// Utility functions
// Move these into inline file?
static inline bool is_intn(int x, int n) {
return -(1 << (n-1)) <= x && x < (1 << (n-1));
}
static inline bool is_int24(int x) { return is_intn(x, 24); }
static inline bool is_int8(int x) { return is_intn(x, 8); }
static inline bool is_uintn(int x, int n) {
return (x & -(1 << n)) == 0;
}
static inline bool is_uint3(int x) { return is_uintn(x, 3); }
static inline bool is_uint4(int x) { return is_uintn(x, 4); }
static inline bool is_uint5(int x) { return is_uintn(x, 5); }
static inline bool is_uint8(int x) { return is_uintn(x, 8); }
static inline bool is_uint12(int x) { return is_uintn(x, 12); }
static inline bool is_uint16(int x) { return is_uintn(x, 16); }
static inline bool is_uint24(int x) { return is_uintn(x, 24); }
} } // namespace v8::internal
#endif // V8_ASSEMBLER_H_

View File

@ -1,368 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#include "v8.h"
#include "ast.h"
#include "scopes.h"
#include "string-stream.h"
namespace v8 { namespace internal {
VariableProxySentinel VariableProxySentinel::this_proxy_(true);
VariableProxySentinel VariableProxySentinel::identifier_proxy_(false);
ValidLeftHandSideSentinel ValidLeftHandSideSentinel::instance_;
Property Property::this_property_(VariableProxySentinel::this_proxy(), NULL, 0);
Call Call::sentinel_(NULL, NULL, false, 0);
// ----------------------------------------------------------------------------
// All the Accept member functions for each syntax tree node type.
#define DECL_ACCEPT(type) \
void type::Accept(Visitor* v) { \
if (v->CheckStackOverflow()) return; \
v->Visit##type(this); \
}
NODE_LIST(DECL_ACCEPT)
#undef DECL_ACCEPT
// ----------------------------------------------------------------------------
// Implementation of other node functionality.
VariableProxy::VariableProxy(Handle<String> name,
bool is_this,
bool inside_with)
: name_(name),
var_(NULL),
is_this_(is_this),
inside_with_(inside_with) {
// names must be canonicalized for fast equality checks
ASSERT(name->IsSymbol());
// at least one access, otherwise no need for a VariableProxy
var_uses_.RecordAccess(1);
}
VariableProxy::VariableProxy(bool is_this)
: is_this_(is_this) {
}
void VariableProxy::BindTo(Variable* var) {
ASSERT(var_ == NULL); // must be bound only once
ASSERT(var != NULL); // must bind
ASSERT((is_this() && var->is_this()) || name_.is_identical_to(var->name()));
// Ideally CONST-ness should match. However, this is very hard to achieve
// because we don't know the exact semantics of conflicting (const and
// non-const) multiple variable declarations, const vars introduced via
// eval() etc. Const-ness and variable declarations are a complete mess
// in JS. Sigh...
var_ = var;
var->var_uses()->RecordUses(&var_uses_);
var->obj_uses()->RecordUses(&obj_uses_);
}
#ifdef DEBUG
const char* LoopStatement::OperatorString() const {
switch (type()) {
case DO_LOOP: return "DO";
case FOR_LOOP: return "FOR";
case WHILE_LOOP: return "WHILE";
}
return NULL;
}
#endif // DEBUG
Token::Value Assignment::binary_op() const {
switch (op_) {
case Token::ASSIGN_BIT_OR: return Token::BIT_OR;
case Token::ASSIGN_BIT_XOR: return Token::BIT_XOR;
case Token::ASSIGN_BIT_AND: return Token::BIT_AND;
case Token::ASSIGN_SHL: return Token::SHL;
case Token::ASSIGN_SAR: return Token::SAR;
case Token::ASSIGN_SHR: return Token::SHR;
case Token::ASSIGN_ADD: return Token::ADD;
case Token::ASSIGN_SUB: return Token::SUB;
case Token::ASSIGN_MUL: return Token::MUL;
case Token::ASSIGN_DIV: return Token::DIV;
case Token::ASSIGN_MOD: return Token::MOD;
default: UNREACHABLE();
}
return Token::ILLEGAL;
}
bool FunctionLiteral::AllowsLazyCompilation() {
return scope()->AllowsLazyCompilation();
}
ObjectLiteral::Property::Property(Literal* key, Expression* value) {
key_ = key;
value_ = value;
Object* k = *key->handle();
if (k->IsSymbol() && Heap::Proto_symbol()->Equals(String::cast(k))) {
kind_ = PROTOTYPE;
} else {
kind_ = value_->AsLiteral() == NULL ? COMPUTED : CONSTANT;
}
}
ObjectLiteral::Property::Property(bool is_getter, FunctionLiteral* value) {
key_ = new Literal(value->name());
value_ = value;
kind_ = is_getter ? GETTER : SETTER;
}
void LabelCollector::AddLabel(Label* label) {
// Add the label to the collector, but discard duplicates.
int length = labels_->length();
for (int i = 0; i < length; i++) {
if (labels_->at(i) == label) return;
}
labels_->Add(label);
}
// ----------------------------------------------------------------------------
// Implementation of Visitor
void Visitor::VisitStatements(ZoneList<Statement*>* statements) {
for (int i = 0; i < statements->length(); i++) {
Visit(statements->at(i));
}
}
void Visitor::VisitExpressions(ZoneList<Expression*>* expressions) {
for (int i = 0; i < expressions->length(); i++) {
// The variable statement visiting code may pass NULL expressions
// to this code. Maybe this should be handled by introducing an
// undefined expression or literal? Revisit this code if this
// changes
Expression* expression = expressions->at(i);
if (expression != NULL) Visit(expression);
}
}
// ----------------------------------------------------------------------------
// Regular expressions
#define MAKE_ACCEPT(Name) \
void* RegExp##Name::Accept(RegExpVisitor* visitor, void* data) { \
return visitor->Visit##Name(this, data); \
}
FOR_EACH_REG_EXP_NODE_TYPE(MAKE_ACCEPT)
#undef MAKE_ACCEPT
#define MAKE_CONVERSION(Name) \
RegExp##Name* RegExpTree::As##Name() { \
return NULL; \
}
FOR_EACH_REG_EXP_NODE_TYPE(MAKE_CONVERSION)
#undef MAKE_CONVERSION
#define MAKE_CONVERSION(Name) \
RegExp##Name* RegExp##Name::As##Name() { \
return this; \
}
FOR_EACH_REG_EXP_NODE_TYPE(MAKE_CONVERSION)
#undef MAKE_CONVERSION
RegExpEmpty RegExpEmpty::kInstance;
// Convert regular expression trees to a simple sexp representation.
// This representation should be different from the input grammar
// in as many cases as possible, to make it more difficult for incorrect
// parses to look as correct ones which is likely if the input and
// output formats are alike.
class RegExpUnparser: public RegExpVisitor {
public:
RegExpUnparser();
void VisitCharacterRange(CharacterRange that);
SmartPointer<char> ToString() { return stream_.ToCString(); }
#define MAKE_CASE(Name) virtual void* Visit##Name(RegExp##Name*, void* data);
FOR_EACH_REG_EXP_NODE_TYPE(MAKE_CASE)
#undef MAKE_CASE
private:
StringStream* stream() { return &stream_; }
HeapStringAllocator alloc_;
StringStream stream_;
};
RegExpUnparser::RegExpUnparser() : stream_(&alloc_) {
}
void* RegExpUnparser::VisitDisjunction(RegExpDisjunction* that, void* data) {
stream()->Add("(|");
for (int i = 0; i < that->nodes()->length(); i++) {
stream()->Add(" ");
that->nodes()->at(i)->Accept(this, data);
}
stream()->Add(")");
return NULL;
}
void* RegExpUnparser::VisitAlternative(RegExpAlternative* that, void* data) {
stream()->Add("(:");
for (int i = 0; i < that->nodes()->length(); i++) {
stream()->Add(" ");
that->nodes()->at(i)->Accept(this, data);
}
stream()->Add(")");
return NULL;
}
void RegExpUnparser::VisitCharacterRange(CharacterRange that) {
if (that.is_character_class()) {
stream()->Add("&%c", that.from());
} else if (that.IsSingleton()) {
stream()->Add("%c", that.from());
} else {
stream()->Add("%c-%c", that.from(), that.to());
}
}
void* RegExpUnparser::VisitCharacterClass(RegExpCharacterClass* that,
void* data) {
if (that->is_negated())
stream()->Add("^");
stream()->Add("[");
for (int i = 0; i < that->ranges()->length(); i++) {
if (i > 0) stream()->Add(" ");
VisitCharacterRange(that->ranges()->at(i));
}
stream()->Add("]");
return NULL;
}
void* RegExpUnparser::VisitAssertion(RegExpAssertion* that, void* data) {
switch (that->type()) {
case RegExpAssertion::START_OF_INPUT:
stream()->Add("@^i");
break;
case RegExpAssertion::END_OF_INPUT:
stream()->Add("@$i");
break;
case RegExpAssertion::START_OF_LINE:
stream()->Add("@^l");
break;
case RegExpAssertion::END_OF_LINE:
stream()->Add("@$l");
break;
case RegExpAssertion::BOUNDARY:
stream()->Add("@b");
break;
case RegExpAssertion::NON_BOUNDARY:
stream()->Add("@B");
break;
}
return NULL;
}
void* RegExpUnparser::VisitAtom(RegExpAtom* that, void* data) {
stream()->Add("'%w'", that->data());
return NULL;
}
void* RegExpUnparser::VisitQuantifier(RegExpQuantifier* that, void* data) {
stream()->Add("(# %i ", that->min());
if (that->max() == RegExpQuantifier::kInfinity) {
stream()->Add("- ");
} else {
stream()->Add("%i ", that->max());
}
stream()->Add(that->is_greedy() ? "g " : "n ");
that->body()->Accept(this, data);
stream()->Add(")");
return NULL;
}
void* RegExpUnparser::VisitCapture(RegExpCapture* that, void* data) {
stream()->Add("(^ ");
that->body()->Accept(this, data);
stream()->Add(")");
return NULL;
}
void* RegExpUnparser::VisitLookahead(RegExpLookahead* that, void* data) {
stream()->Add("(-> ");
stream()->Add(that->is_positive() ? "+ " : "- ");
that->body()->Accept(this, data);
stream()->Add(")");
return NULL;
}
void* RegExpUnparser::VisitBackreference(RegExpBackreference* that,
void* data) {
stream()->Add("(<- %i)", that->index());
return NULL;
}
void* RegExpUnparser::VisitEmpty(RegExpEmpty* that, void* data) {
stream()->Put('%');
return NULL;
}
SmartPointer<char> RegExpTree::ToString() {
RegExpUnparser unparser;
Accept(&unparser, NULL);
return unparser.ToString();
}
} } // namespace v8::internal

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,74 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#ifndef V8_BOOTSTRAPPER_H_
#define V8_BOOTSTRAPPER_H_
namespace v8 { namespace internal {
// The Boostrapper is the public interface for creating a JavaScript global
// context.
class Bootstrapper : public AllStatic {
public:
// Requires: Heap::Setup has been called.
static void Initialize(bool create_heap_objects);
static void TearDown();
// Creates a JavaScript Global Context with initial object graph.
// The returned value is a global handle casted to V8Environment*.
static Handle<Context> CreateEnvironment(
Handle<Object> global_object,
v8::Handle<v8::ObjectTemplate> global_template,
v8::ExtensionConfiguration* extensions);
// Detach the environment from its outer global object.
static void DetachGlobal(Handle<Context> env);
// Traverses the pointers for memory manangment.
static void Iterate(ObjectVisitor* v);
// Accessors for the native scripts cache. Used in lazy loading.
static Handle<String> NativesSourceLookup(int index);
static bool NativesCacheLookup(Vector<const char> name,
Handle<JSFunction>* handle);
static void NativesCacheAdd(Vector<const char> name, Handle<JSFunction> fun);
// Append code that needs fixup at the end of boot strapping.
static void AddFixup(Code* code, MacroAssembler* masm);
// Tells whether boostrapping is active.
static bool IsActive();
// Encoding/decoding support for fixup flags.
class FixupFlagsIsPCRelative: public BitField<bool, 0, 1> {};
class FixupFlagsArgumentsCount: public BitField<uint32_t, 1, 32-1> {};
};
}} // namespace v8::internal
#endif // V8_BOOTSTRAPPER_H_

View File

@ -1,821 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#include "v8.h"
#include "codegen-inl.h"
#include "debug.h"
#include "runtime.h"
namespace v8 { namespace internal {
#define __ masm->
void Builtins::Generate_Adaptor(MacroAssembler* masm, CFunctionId id) {
// TODO(1238487): Don't pass the function in a static variable.
__ mov(ip, Operand(ExternalReference::builtin_passed_function()));
__ str(r1, MemOperand(ip, 0));
// The actual argument count has already been loaded into register
// r0, but JumpToBuiltin expects r0 to contain the number of
// arguments including the receiver.
__ add(r0, r0, Operand(1));
__ JumpToBuiltin(ExternalReference(id));
}
void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : number of arguments
// -- r1 : constructor function
// -- lr : return address
// -- sp[...]: constructor arguments
// -----------------------------------
// Enter a construct frame.
__ EnterConstructFrame();
// Preserve the two incoming parameters
__ mov(r0, Operand(r0, LSL, kSmiTagSize));
__ push(r0); // smi-tagged arguments count
__ push(r1); // constructor function
// Allocate the new receiver object.
__ push(r1); // argument for Runtime_NewObject
__ CallRuntime(Runtime::kNewObject, 1);
__ push(r0); // save the receiver
// Push the function and the allocated receiver from the stack.
// sp[0]: receiver (newly allocated object)
// sp[1]: constructor function
// sp[2]: number of arguments (smi-tagged)
__ ldr(r1, MemOperand(sp, kPointerSize));
__ push(r1); // function
__ push(r0); // receiver
// Reload the number of arguments from the stack.
// r1: constructor function
// sp[0]: receiver
// sp[1]: constructor function
// sp[2]: receiver
// sp[3]: constructor function
// sp[4]: number of arguments (smi-tagged)
__ ldr(r3, MemOperand(sp, 4 * kPointerSize));
// Setup pointer to last argument.
__ add(r2, fp, Operand(StandardFrameConstants::kCallerSPOffset));
// Setup number of arguments for function call below
__ mov(r0, Operand(r3, LSR, kSmiTagSize));
// Copy arguments and receiver to the expression stack.
// r0: number of arguments
// r2: address of last argument (caller sp)
// r1: constructor function
// r3: number of arguments (smi-tagged)
// sp[0]: receiver
// sp[1]: constructor function
// sp[2]: receiver
// sp[3]: constructor function
// sp[4]: number of arguments (smi-tagged)
Label loop, entry;
__ b(&entry);
__ bind(&loop);
__ ldr(ip, MemOperand(r2, r3, LSL, kPointerSizeLog2 - 1));
__ push(ip);
__ bind(&entry);
__ sub(r3, r3, Operand(2), SetCC);
__ b(ge, &loop);
// Call the function.
// r0: number of arguments
// r1: constructor function
ParameterCount actual(r0);
__ InvokeFunction(r1, actual, CALL_FUNCTION);
// Pop the function from the stack.
// sp[0]: constructor function
// sp[2]: receiver
// sp[3]: constructor function
// sp[4]: number of arguments (smi-tagged)
__ pop();
// Restore context from the frame.
// r0: result
// sp[0]: receiver
// sp[1]: constructor function
// sp[2]: number of arguments (smi-tagged)
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
// If the result is an object (in the ECMA sense), we should get rid
// of the receiver and use the result; see ECMA-262 section 13.2.2-7
// on page 74.
Label use_receiver, exit;
// If the result is a smi, it is *not* an object in the ECMA sense.
// r0: result
// sp[0]: receiver (newly allocated object)
// sp[1]: constructor function
// sp[2]: number of arguments (smi-tagged)
__ tst(r0, Operand(kSmiTagMask));
__ b(eq, &use_receiver);
// If the type of the result (stored in its map) is less than
// FIRST_JS_OBJECT_TYPE, it is not an object in the ECMA sense.
__ ldr(r3, FieldMemOperand(r0, HeapObject::kMapOffset));
__ ldrb(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset));
__ cmp(r3, Operand(FIRST_JS_OBJECT_TYPE));
__ b(ge, &exit);
// Throw away the result of the constructor invocation and use the
// on-stack receiver as the result.
__ bind(&use_receiver);
__ ldr(r0, MemOperand(sp));
// Remove receiver from the stack, remove caller arguments, and
// return.
__ bind(&exit);
// r0: result
// sp[0]: receiver (newly allocated object)
// sp[1]: constructor function
// sp[2]: number of arguments (smi-tagged)
__ ldr(r1, MemOperand(sp, 2 * kPointerSize));
__ LeaveConstructFrame();
__ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - 1));
__ add(sp, sp, Operand(kPointerSize));
__ mov(pc, Operand(lr));
}
static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
bool is_construct) {
// Called from Generate_JS_Entry
// r0: code entry
// r1: function
// r2: receiver
// r3: argc
// r4: argv
// r5-r7, cp may be clobbered
// Clear the context before we push it when entering the JS frame.
__ mov(cp, Operand(0));
// Enter an internal frame.
__ EnterInternalFrame();
// Setup the context from the function argument.
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
// Push the function and the receiver onto the stack.
__ push(r1);
__ push(r2);
// Copy arguments to the stack in a loop.
// r1: function
// r3: argc
// r4: argv, i.e. points to first arg
Label loop, entry;
__ add(r2, r4, Operand(r3, LSL, kPointerSizeLog2));
// r2 points past last arg.
__ b(&entry);
__ bind(&loop);
__ ldr(r0, MemOperand(r4, kPointerSize, PostIndex)); // read next parameter
__ ldr(r0, MemOperand(r0)); // dereference handle
__ push(r0); // push parameter
__ bind(&entry);
__ cmp(r4, Operand(r2));
__ b(ne, &loop);
// Initialize all JavaScript callee-saved registers, since they will be seen
// by the garbage collector as part of handlers.
__ mov(r4, Operand(Factory::undefined_value()));
__ mov(r5, Operand(r4));
__ mov(r6, Operand(r4));
__ mov(r7, Operand(r4));
if (kR9Available == 1)
__ mov(r9, Operand(r4));
// Invoke the code and pass argc as r0.
__ mov(r0, Operand(r3));
if (is_construct) {
__ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
RelocInfo::CODE_TARGET);
} else {
ParameterCount actual(r0);
__ InvokeFunction(r1, actual, CALL_FUNCTION);
}
// Exit the JS frame and remove the parameters (except function), and return.
// Respect ABI stack constraint.
__ LeaveInternalFrame();
__ mov(pc, lr);
// r0: result
}
void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
Generate_JSEntryTrampolineHelper(masm, false);
}
void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
Generate_JSEntryTrampolineHelper(masm, true);
}
void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
// 1. Make sure we have at least one argument.
// r0: actual number of argument
{ Label done;
__ tst(r0, Operand(r0));
__ b(ne, &done);
__ mov(r2, Operand(Factory::undefined_value()));
__ push(r2);
__ add(r0, r0, Operand(1));
__ bind(&done);
}
// 2. Get the function to call from the stack.
// r0: actual number of argument
{ Label done, non_function, function;
__ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
__ tst(r1, Operand(kSmiTagMask));
__ b(eq, &non_function);
__ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
__ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
__ cmp(r2, Operand(JS_FUNCTION_TYPE));
__ b(eq, &function);
// Non-function called: Clear the function to force exception.
__ bind(&non_function);
__ mov(r1, Operand(0));
__ b(&done);
// Change the context eagerly because it will be used below to get the
// right global object.
__ bind(&function);
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
__ bind(&done);
}
// 3. Make sure first argument is an object; convert if necessary.
// r0: actual number of arguments
// r1: function
{ Label call_to_object, use_global_receiver, patch_receiver, done;
__ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
__ ldr(r2, MemOperand(r2, -kPointerSize));
// r0: actual number of arguments
// r1: function
// r2: first argument
__ tst(r2, Operand(kSmiTagMask));
__ b(eq, &call_to_object);
__ mov(r3, Operand(Factory::null_value()));
__ cmp(r2, r3);
__ b(eq, &use_global_receiver);
__ mov(r3, Operand(Factory::undefined_value()));
__ cmp(r2, r3);
__ b(eq, &use_global_receiver);
__ ldr(r3, FieldMemOperand(r2, HeapObject::kMapOffset));
__ ldrb(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset));
__ cmp(r3, Operand(FIRST_JS_OBJECT_TYPE));
__ b(lt, &call_to_object);
__ cmp(r3, Operand(LAST_JS_OBJECT_TYPE));
__ b(le, &done);
__ bind(&call_to_object);
__ EnterInternalFrame();
// Store number of arguments and function across the call into the runtime.
__ mov(r0, Operand(r0, LSL, kSmiTagSize));
__ push(r0);
__ push(r1);
__ push(r2);
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS);
__ mov(r2, r0);
// Restore number of arguments and function.
__ pop(r1);
__ pop(r0);
__ mov(r0, Operand(r0, ASR, kSmiTagSize));
__ LeaveInternalFrame();
__ b(&patch_receiver);
// Use the global receiver object from the called function as the receiver.
__ bind(&use_global_receiver);
const int kGlobalIndex =
Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
__ ldr(r2, FieldMemOperand(cp, kGlobalIndex));
__ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
__ bind(&patch_receiver);
__ add(r3, sp, Operand(r0, LSL, kPointerSizeLog2));
__ str(r2, MemOperand(r3, -kPointerSize));
__ bind(&done);
}
// 4. Shift stuff one slot down the stack
// r0: actual number of arguments (including call() receiver)
// r1: function
{ Label loop;
// Calculate the copy start address (destination). Copy end address is sp.
__ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
__ add(r2, r2, Operand(kPointerSize)); // copy receiver too
__ bind(&loop);
__ ldr(ip, MemOperand(r2, -kPointerSize));
__ str(ip, MemOperand(r2));
__ sub(r2, r2, Operand(kPointerSize));
__ cmp(r2, sp);
__ b(ne, &loop);
}
// 5. Adjust the actual number of arguments and remove the top element.
// r0: actual number of arguments (including call() receiver)
// r1: function
__ sub(r0, r0, Operand(1));
__ add(sp, sp, Operand(kPointerSize));
// 6. Get the code for the function or the non-function builtin.
// If number of expected arguments matches, then call. Otherwise restart
// the arguments adaptor stub.
// r0: actual number of arguments
// r1: function
{ Label invoke;
__ tst(r1, r1);
__ b(ne, &invoke);
__ mov(r2, Operand(0)); // expected arguments is 0 for CALL_NON_FUNCTION
__ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
__ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
RelocInfo::CODE_TARGET);
__ bind(&invoke);
__ ldr(r3, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
__ ldr(r2,
FieldMemOperand(r3,
SharedFunctionInfo::kFormalParameterCountOffset));
__ ldr(r3,
MemOperand(r3, SharedFunctionInfo::kCodeOffset - kHeapObjectTag));
__ add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag));
__ cmp(r2, r0); // Check formal and actual parameter counts.
__ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
RelocInfo::CODE_TARGET, ne);
// 7. Jump to the code in r3 without checking arguments.
ParameterCount expected(0);
__ InvokeCode(r3, expected, expected, JUMP_FUNCTION);
}
}
void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
const int kIndexOffset = -5 * kPointerSize;
const int kLimitOffset = -4 * kPointerSize;
const int kArgsOffset = 2 * kPointerSize;
const int kRecvOffset = 3 * kPointerSize;
const int kFunctionOffset = 4 * kPointerSize;
__ EnterInternalFrame();
__ ldr(r0, MemOperand(fp, kFunctionOffset)); // get the function
__ push(r0);
__ ldr(r0, MemOperand(fp, kArgsOffset)); // get the args array
__ push(r0);
__ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_JS);
// Eagerly check for stack-overflow before starting to push the arguments.
// r0: number of arguments
Label okay;
ExternalReference stack_guard_limit_address =
ExternalReference::address_of_stack_guard_limit();
__ mov(r2, Operand(stack_guard_limit_address));
__ ldr(r2, MemOperand(r2));
__ sub(r2, sp, r2);
__ sub(r2, r2, Operand(3 * kPointerSize)); // limit, index, receiver
__ cmp(r2, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
__ b(hi, &okay);
// Out of stack space.
__ ldr(r1, MemOperand(fp, kFunctionOffset));
__ push(r1);
__ push(r0);
__ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_JS);
// Push current limit and index.
__ bind(&okay);
__ push(r0); // limit
__ mov(r1, Operand(0)); // initial index
__ push(r1);
// Change context eagerly to get the right global object if necessary.
__ ldr(r0, MemOperand(fp, kFunctionOffset));
__ ldr(cp, FieldMemOperand(r0, JSFunction::kContextOffset));
// Compute the receiver.
Label call_to_object, use_global_receiver, push_receiver;
__ ldr(r0, MemOperand(fp, kRecvOffset));
__ tst(r0, Operand(kSmiTagMask));
__ b(eq, &call_to_object);
__ mov(r1, Operand(Factory::null_value()));
__ cmp(r0, r1);
__ b(eq, &use_global_receiver);
__ mov(r1, Operand(Factory::undefined_value()));
__ cmp(r0, r1);
__ b(eq, &use_global_receiver);
// Check if the receiver is already a JavaScript object.
// r0: receiver
__ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
__ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
__ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE));
__ b(lt, &call_to_object);
__ cmp(r1, Operand(LAST_JS_OBJECT_TYPE));
__ b(le, &push_receiver);
// Convert the receiver to a regular object.
// r0: receiver
__ bind(&call_to_object);
__ push(r0);
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS);
__ b(&push_receiver);
// Use the current global receiver object as the receiver.
__ bind(&use_global_receiver);
const int kGlobalOffset =
Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
__ ldr(r0, FieldMemOperand(cp, kGlobalOffset));
__ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
// Push the receiver.
// r0: receiver
__ bind(&push_receiver);
__ push(r0);
// Copy all arguments from the array to the stack.
Label entry, loop;
__ ldr(r0, MemOperand(fp, kIndexOffset));
__ b(&entry);
// Load the current argument from the arguments array and push it to the
// stack.
// r0: current argument index
__ bind(&loop);
__ ldr(r1, MemOperand(fp, kArgsOffset));
__ push(r1);
__ push(r0);
// Call the runtime to access the property in the arguments array.
__ CallRuntime(Runtime::kGetProperty, 2);
__ push(r0);
// Use inline caching to access the arguments.
__ ldr(r0, MemOperand(fp, kIndexOffset));
__ add(r0, r0, Operand(1 << kSmiTagSize));
__ str(r0, MemOperand(fp, kIndexOffset));
// Test if the copy loop has finished copying all the elements from the
// arguments object.
__ bind(&entry);
__ ldr(r1, MemOperand(fp, kLimitOffset));
__ cmp(r0, r1);
__ b(ne, &loop);
// Invoke the function.
ParameterCount actual(r0);
__ mov(r0, Operand(r0, ASR, kSmiTagSize));
__ ldr(r1, MemOperand(fp, kFunctionOffset));
__ InvokeFunction(r1, actual, CALL_FUNCTION);
// Tear down the internal frame and remove function, receiver and args.
__ LeaveInternalFrame();
__ add(sp, sp, Operand(3 * kPointerSize));
__ mov(pc, lr);
}
static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
__ mov(r0, Operand(r0, LSL, kSmiTagSize));
__ mov(r4, Operand(ArgumentsAdaptorFrame::SENTINEL));
__ stm(db_w, sp, r0.bit() | r1.bit() | r4.bit() | fp.bit() | lr.bit());
__ add(fp, sp, Operand(3 * kPointerSize));
}
static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : result being passed through
// -----------------------------------
// Get the number of arguments passed (as a smi), tear down the frame and
// then tear down the parameters.
__ ldr(r1, MemOperand(fp, -3 * kPointerSize));
__ mov(sp, fp);
__ ldm(ia_w, sp, fp.bit() | lr.bit());
__ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
__ add(sp, sp, Operand(kPointerSize)); // adjust for receiver
}
void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : actual number of arguments
// -- r1 : function (passed through to callee)
// -- r2 : expected number of arguments
// -- r3 : code entry to call
// -----------------------------------
Label invoke, dont_adapt_arguments;
Label enough, too_few;
__ cmp(r0, Operand(r2));
__ b(lt, &too_few);
__ cmp(r2, Operand(SharedFunctionInfo::kDontAdaptArgumentsSentinel));
__ b(eq, &dont_adapt_arguments);
{ // Enough parameters: actual >= excpected
__ bind(&enough);
EnterArgumentsAdaptorFrame(masm);
// Calculate copy start address into r0 and copy end address into r2.
// r0: actual number of arguments as a smi
// r1: function
// r2: expected number of arguments
// r3: code entry to call
__ add(r0, fp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
// adjust for return address and receiver
__ add(r0, r0, Operand(2 * kPointerSize));
__ sub(r2, r0, Operand(r2, LSL, kPointerSizeLog2));
// Copy the arguments (including the receiver) to the new stack frame.
// r0: copy start address
// r1: function
// r2: copy end address
// r3: code entry to call
Label copy;
__ bind(&copy);
__ ldr(ip, MemOperand(r0, 0));
__ push(ip);
__ cmp(r0, r2); // Compare before moving to next argument.
__ sub(r0, r0, Operand(kPointerSize));
__ b(ne, &copy);
__ b(&invoke);
}
{ // Too few parameters: Actual < expected
__ bind(&too_few);
EnterArgumentsAdaptorFrame(masm);
// Calculate copy start address into r0 and copy end address is fp.
// r0: actual number of arguments as a smi
// r1: function
// r2: expected number of arguments
// r3: code entry to call
__ add(r0, fp, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
// Copy the arguments (including the receiver) to the new stack frame.
// r0: copy start address
// r1: function
// r2: expected number of arguments
// r3: code entry to call
Label copy;
__ bind(&copy);
// Adjust load for return address and receiver.
__ ldr(ip, MemOperand(r0, 2 * kPointerSize));
__ push(ip);
__ cmp(r0, fp); // Compare before moving to next argument.
__ sub(r0, r0, Operand(kPointerSize));
__ b(ne, &copy);
// Fill the remaining expected arguments with undefined.
// r1: function
// r2: expected number of arguments
// r3: code entry to call
__ mov(ip, Operand(Factory::undefined_value()));
__ sub(r2, fp, Operand(r2, LSL, kPointerSizeLog2));
__ sub(r2, r2, Operand(4 * kPointerSize)); // Adjust for frame.
Label fill;
__ bind(&fill);
__ push(ip);
__ cmp(sp, r2);
__ b(ne, &fill);
}
// Call the entry point.
__ bind(&invoke);
__ Call(r3);
// Exit frame and return.
LeaveArgumentsAdaptorFrame(masm);
__ mov(pc, lr);
// -------------------------------------------
// Dont adapt arguments.
// -------------------------------------------
__ bind(&dont_adapt_arguments);
__ mov(pc, r3);
}
static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
RegList pointer_regs) {
// Save the content of all general purpose registers in memory. This copy in
// memory is later pushed onto the JS expression stack for the fake JS frame
// generated and also to the C frame generated on top of that. In the JS
// frame ONLY the registers containing pointers will be pushed on the
// expression stack. This causes the GC to update these pointers so that
// they will have the correct value when returning from the debugger.
__ SaveRegistersToMemory(kJSCallerSaved);
// This is a direct call from a debug breakpoint. To build a fake JS frame
// with no parameters push a function and a receiver, keep the current
// return address in lr, and set r0 to zero.
__ mov(ip, Operand(ExternalReference::the_hole_value_location()));
__ ldr(r3, MemOperand(ip));
__ mov(r0, Operand(0)); // Null receiver and zero arguments.
__ stm(db_w, sp, r0.bit() | r3.bit()); // push function and receiver
// r0: number of arguments.
// What follows is an inlined version of EnterJSFrame(0, 0).
// It needs to be kept in sync if any calling conventions are changed.
// Compute parameter pointer before making changes
// ip = sp + kPointerSize*(args_len+1); // +1 for receiver, args_len == 0
__ add(ip, sp, Operand(kPointerSize));
__ mov(r3, Operand(0)); // args_len to be saved
__ mov(r2, Operand(cp)); // context to be saved
// push in reverse order: context (r2), args_len (r3), caller_pp, caller_fp,
// sp_on_exit (ip == pp), return address
__ stm(db_w, sp, r2.bit() | r3.bit() | pp.bit() | fp.bit() |
ip.bit() | lr.bit());
// Setup new frame pointer.
__ add(fp, sp, Operand(-StandardFrameConstants::kContextOffset));
__ mov(pp, Operand(ip)); // setup new parameter pointer
// r0 is already set to 0 as spare slot to store caller code object during GC
__ push(r0); // code pointer
// Inlined EnterJSFrame ends here.
// Store the registers containing object pointers on the expression stack to
// make sure that these are correctly updated during GC.
// Use sp as base to push.
__ CopyRegistersFromMemoryToStack(sp, pointer_regs);
#ifdef DEBUG
__ RecordComment("// Calling from debug break to runtime - come in - over");
#endif
// r0 is already 0, no arguments
__ mov(r1, Operand(ExternalReference::debug_break()));
CEntryDebugBreakStub ceb;
__ CallStub(&ceb);
// Restore the register values containing object pointers from the expression
// stack in the reverse order as they where pushed.
// Use sp as base to pop.
__ CopyRegistersFromStackToMemory(sp, r3, pointer_regs);
// What follows is an inlined version of ExitJSFrame(0).
// It needs to be kept in sync if any calling conventions are changed.
// NOTE: loading the return address to lr and discarding the (fake) function
// is an addition to this inlined copy.
__ mov(sp, Operand(fp)); // respect ABI stack constraint
__ ldm(ia, sp, pp.bit() | fp.bit() | sp.bit() | lr.bit());
__ pop(); // discard fake function
// Inlined ExitJSFrame ends here.
// Finally restore all registers.
__ RestoreRegistersFromMemory(kJSCallerSaved);
// Now that the break point has been handled, resume normal execution by
// jumping to the target address intended by the caller and that was
// overwritten by the address of DebugBreakXXX.
__ mov(ip, Operand(ExternalReference(Debug_Address::AfterBreakTarget())));
__ ldr(ip, MemOperand(ip));
__ Jump(ip);
}
void Builtins::Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
// Calling convention for IC load (from ic-arm.cc).
// ----------- S t a t e -------------
// -- r0 : receiver
// -- r2 : name
// -- lr : return address
// -- [sp] : receiver
// -----------------------------------
// Registers r0 and r2 contain objects that needs to be pushed on the
// expression stack of the fake JS frame.
Generate_DebugBreakCallHelper(masm, r0.bit() | r2.bit());
}
void Builtins::Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
// Calling convention for IC store (from ic-arm.cc).
// ----------- S t a t e -------------
// -- r0 : receiver
// -- r2 : name
// -- lr : return address
// -- [sp] : receiver
// -----------------------------------
// Registers r0 and r2 contain objects that needs to be pushed on the
// expression stack of the fake JS frame.
Generate_DebugBreakCallHelper(masm, r0.bit() | r2.bit());
}
void Builtins::Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
// Keyed load IC not implemented on ARM.
}
void Builtins::Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
// Keyed store IC not implemented on ARM.
}
void Builtins::Generate_CallIC_DebugBreak(MacroAssembler* masm) {
// Calling convention for IC call (from ic-arm.cc)
// ----------- S t a t e -------------
// -- r0: number of arguments
// -- r1: receiver
// -- lr: return address
// -----------------------------------
// Register r1 contains an object that needs to be pushed on the expression
// stack of the fake JS frame. r0 is the actual number of arguments not
// encoded as a smi, therefore it cannot be on the expression stack of the
// fake JS frame as it can easily be an invalid pointer (e.g. 1). r0 will be
// pushed on the stack of the C frame and restored from there.
Generate_DebugBreakCallHelper(masm, r1.bit());
}
void Builtins::Generate_ConstructCall_DebugBreak(MacroAssembler* masm) {
// In places other than IC call sites it is expected that r0 is TOS which
// is an object - this is not generally the case so this should be used with
// care.
Generate_DebugBreakCallHelper(masm, r0.bit());
}
void Builtins::Generate_Return_DebugBreak(MacroAssembler* masm) {
// In places other than IC call sites it is expected that r0 is TOS which
// is an object - this is not generally the case so this should be used with
// care.
Generate_DebugBreakCallHelper(masm, r0.bit());
}
void Builtins::Generate_Return_DebugBreakEntry(MacroAssembler* masm) {
// Generate nothing as this handling of debug break return is not done this
// way on ARM - yet.
}
void Builtins::Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) {
// Generate nothing as CodeStub CallFunction is not used on ARM.
}
#undef __
} } // namespace v8::internal

View File

@ -1,902 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#include "v8.h"
#include "codegen-inl.h"
#include "debug.h"
#include "runtime.h"
namespace v8 { namespace internal {
#define __ masm->
void Builtins::Generate_Adaptor(MacroAssembler* masm, CFunctionId id) {
// TODO(1238487): Don't pass the function in a static variable.
ExternalReference passed = ExternalReference::builtin_passed_function();
__ mov(Operand::StaticVariable(passed), edi);
// The actual argument count has already been loaded into register
// eax, but JumpToBuiltin expects eax to contain the number of
// arguments including the receiver.
__ inc(eax);
__ JumpToBuiltin(ExternalReference(id));
}
void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax: number of arguments
// -- edi: constructor function
// -----------------------------------
// Enter a construct frame.
__ EnterConstructFrame();
// Store a smi-tagged arguments count on the stack.
__ shl(eax, kSmiTagSize);
__ push(eax);
// Push the function to invoke on the stack.
__ push(edi);
// Try to allocate the object without transitioning into C code. If any of the
// preconditions is not met, the code bails out to the runtime call.
Label rt_call, allocated;
if (FLAG_inline_new) {
Label undo_allocation;
ExternalReference debug_step_in_fp =
ExternalReference::debug_step_in_fp_address();
__ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
__ j(not_equal, &rt_call);
// Check that function is not a Smi.
__ test(edi, Immediate(kSmiTagMask));
__ j(zero, &rt_call);
// Check that function is a JSFunction
__ mov(eax, FieldOperand(edi, JSFunction::kMapOffset));
__ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset));
__ cmp(eax, JS_FUNCTION_TYPE);
__ j(not_equal, &rt_call);
// Verified that the constructor is a JSFunction.
// Load the initial map and verify that it is in fact a map.
// edi: constructor
__ mov(eax, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
// Will both indicate a NULL and a Smi
__ test(eax, Immediate(kSmiTagMask));
__ j(zero, &rt_call);
// edi: constructor
// eax: initial map (if proven valid below)
__ mov(ebx, FieldOperand(eax, JSFunction::kMapOffset));
__ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
__ cmp(ebx, MAP_TYPE);
__ j(not_equal, &rt_call);
// Check that the constructor is not constructing a JSFunction (see comments
// in Runtime_NewObject in runtime.cc). In which case the initial map's
// instance type would be JS_FUNCTION_TYPE.
// edi: constructor
// eax: initial map
__ movzx_b(ebx, FieldOperand(eax, Map::kInstanceTypeOffset));
__ cmp(ebx, JS_FUNCTION_TYPE);
__ j(equal, &rt_call);
// Now allocate the JSObject on the heap.
// edi: constructor
// eax: initial map
__ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset));
__ shl(edi, kPointerSizeLog2);
// Make sure that the maximum heap object size will never cause us
// problem here, because it is always greater than the maximum
// instance size that can be represented in a byte.
ASSERT(Heap::MaxHeapObjectSize() >= (1 << kBitsPerByte));
ExternalReference new_space_allocation_top =
ExternalReference::new_space_allocation_top_address();
__ mov(ebx, Operand::StaticVariable(new_space_allocation_top));
__ add(edi, Operand(ebx)); // Calculate new top
ExternalReference new_space_allocation_limit =
ExternalReference::new_space_allocation_limit_address();
__ cmp(edi, Operand::StaticVariable(new_space_allocation_limit));
__ j(greater_equal, &rt_call);
// Allocated the JSObject, now initialize the fields.
// eax: initial map
// ebx: JSObject
// edi: start of next object
__ mov(Operand(ebx, JSObject::kMapOffset), eax);
__ mov(Operand(ecx), Factory::empty_fixed_array());
__ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx);
__ mov(Operand(ebx, JSObject::kElementsOffset), ecx);
// Set extra fields in the newly allocated object.
// eax: initial map
// ebx: JSObject
// edi: start of next object
{ Label loop, entry;
__ mov(Operand(edx), Factory::undefined_value());
__ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
__ jmp(&entry);
__ bind(&loop);
__ mov(Operand(ecx, 0), edx);
__ add(Operand(ecx), Immediate(kPointerSize));
__ bind(&entry);
__ cmp(ecx, Operand(edi));
__ j(less, &loop);
}
// Mostly done with the JSObject. Add the heap tag and store the new top, so
// that we can continue and jump into the continuation code at any time from
// now on. Any failures need to undo the setting of the new top, so that the
// heap is in a consistent state and verifiable.
// eax: initial map
// ebx: JSObject
// edi: start of next object
__ or_(Operand(ebx), Immediate(kHeapObjectTag));
__ mov(Operand::StaticVariable(new_space_allocation_top), edi);
// Check if a properties array should be setup and allocate one if needed.
// Otherwise initialize the properties to the empty_fixed_array as well.
// eax: initial map
// ebx: JSObject
// edi: start of next object
__ movzx_b(edx, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset));
__ movzx_b(ecx, FieldOperand(eax, Map::kInObjectPropertiesOffset));
// Calculate unused properties past the end of the in-object properties.
__ sub(edx, Operand(ecx));
__ test(edx, Operand(edx));
// Done if no extra properties are to be allocated.
__ j(zero, &allocated);
// Scale the number of elements by pointer size and add the header for
// FixedArrays to the start of the next object calculation from above.
// eax: initial map
// ebx: JSObject
// edi: start of next object (will be start of FixedArray)
// edx: number of elements in properties array
ASSERT(Heap::MaxHeapObjectSize() >
(FixedArray::kHeaderSize + 255*kPointerSize));
__ lea(ecx, Operand(edi, edx, times_4, FixedArray::kHeaderSize));
__ cmp(ecx, Operand::StaticVariable(new_space_allocation_limit));
__ j(greater_equal, &undo_allocation);
__ mov(Operand::StaticVariable(new_space_allocation_top), ecx);
// Initialize the FixedArray.
// ebx: JSObject
// edi: FixedArray
// edx: number of elements
// ecx: start of next object
__ mov(eax, Factory::fixed_array_map());
__ mov(Operand(edi, JSObject::kMapOffset), eax); // setup the map
__ mov(Operand(edi, Array::kLengthOffset), edx); // and length
// Initialize the fields to undefined.
// ebx: JSObject
// edi: FixedArray
// ecx: start of next object
{ Label loop, entry;
__ mov(Operand(edx), Factory::undefined_value());
__ lea(eax, Operand(edi, FixedArray::kHeaderSize));
__ jmp(&entry);
__ bind(&loop);
__ mov(Operand(eax, 0), edx);
__ add(Operand(eax), Immediate(kPointerSize));
__ bind(&entry);
__ cmp(eax, Operand(ecx));
__ j(less, &loop);
}
// Store the initialized FixedArray into the properties field of
// the JSObject
// ebx: JSObject
// edi: FixedArray
__ or_(Operand(edi), Immediate(kHeapObjectTag)); // add the heap tag
__ mov(FieldOperand(ebx, JSObject::kPropertiesOffset), edi);
// Continue with JSObject being successfully allocated
// ebx: JSObject
__ jmp(&allocated);
// Undo the setting of the new top so that the heap is verifiable. For
// example, the map's unused properties potentially do not match the
// allocated objects unused properties.
// ebx: JSObject (previous new top)
__ bind(&undo_allocation);
__ xor_(Operand(ebx), Immediate(kHeapObjectTag)); // clear the heap tag
__ mov(Operand::StaticVariable(new_space_allocation_top), ebx);
}
// Allocate the new receiver object using the runtime call.
// edi: function (constructor)
__ bind(&rt_call);
// Must restore edi (constructor) before calling runtime.
__ mov(edi, Operand(esp, 0));
__ push(edi);
__ CallRuntime(Runtime::kNewObject, 1);
__ mov(ebx, Operand(eax)); // store result in ebx
// New object allocated.
// ebx: newly allocated object
__ bind(&allocated);
// Retrieve the function from the stack.
__ pop(edi);
// Retrieve smi-tagged arguments count from the stack.
__ mov(eax, Operand(esp, 0));
__ shr(eax, kSmiTagSize);
// Push the allocated receiver to the stack. We need two copies
// because we may have to return the original one and the calling
// conventions dictate that the called function pops the receiver.
__ push(ebx);
__ push(ebx);
// Setup pointer to last argument.
__ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
// Copy arguments and receiver to the expression stack.
Label loop, entry;
__ mov(ecx, Operand(eax));
__ jmp(&entry);
__ bind(&loop);
__ push(Operand(ebx, ecx, times_4, 0));
__ bind(&entry);
__ dec(ecx);
__ j(greater_equal, &loop);
// Call the function.
ParameterCount actual(eax);
__ InvokeFunction(edi, actual, CALL_FUNCTION);
// Restore context from the frame.
__ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
// If the result is an object (in the ECMA sense), we should get rid
// of the receiver and use the result; see ECMA-262 section 13.2.2-7
// on page 74.
Label use_receiver, exit;
// If the result is a smi, it is *not* an object in the ECMA sense.
__ test(eax, Immediate(kSmiTagMask));
__ j(zero, &use_receiver, not_taken);
// If the type of the result (stored in its map) is less than
// FIRST_JS_OBJECT_TYPE, it is not an object in the ECMA sense.
__ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
__ cmp(ecx, FIRST_JS_OBJECT_TYPE);
__ j(greater_equal, &exit, not_taken);
// Throw away the result of the constructor invocation and use the
// on-stack receiver as the result.
__ bind(&use_receiver);
__ mov(eax, Operand(esp, 0));
// Restore the arguments count and leave the construct frame.
__ bind(&exit);
__ mov(ebx, Operand(esp, kPointerSize)); // get arguments count
__ LeaveConstructFrame();
// Remove caller arguments from the stack and return.
ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
__ pop(ecx);
__ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
__ push(ecx);
__ ret(0);
}
static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
bool is_construct) {
// Clear the context before we push it when entering the JS frame.
__ xor_(esi, Operand(esi)); // clear esi
// Enter an internal frame.
__ EnterInternalFrame();
// Load the previous frame pointer (ebx) to access C arguments
__ mov(ebx, Operand(ebp, 0));
// Get the function from the frame and setup the context.
__ mov(ecx, Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
__ mov(esi, FieldOperand(ecx, JSFunction::kContextOffset));
// Push the function and the receiver onto the stack.
__ push(ecx);
__ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
// Load the number of arguments and setup pointer to the arguments.
__ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset));
__ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset));
// Copy arguments to the stack in a loop.
Label loop, entry;
__ xor_(ecx, Operand(ecx)); // clear ecx
__ jmp(&entry);
__ bind(&loop);
__ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv
__ push(Operand(edx, 0)); // dereference handle
__ inc(Operand(ecx));
__ bind(&entry);
__ cmp(ecx, Operand(eax));
__ j(not_equal, &loop);
// Get the function from the stack and call it.
__ mov(edi, Operand(esp, eax, times_4, +1 * kPointerSize)); // +1 ~ receiver
// Invoke the code.
if (is_construct) {
__ call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
RelocInfo::CODE_TARGET);
} else {
ParameterCount actual(eax);
__ InvokeFunction(edi, actual, CALL_FUNCTION);
}
// Exit the JS frame. Notice that this also removes the empty
// context and the function left on the stack by the code
// invocation.
__ LeaveInternalFrame();
__ ret(1 * kPointerSize); // remove receiver
}
void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
Generate_JSEntryTrampolineHelper(masm, false);
}
void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
Generate_JSEntryTrampolineHelper(masm, true);
}
void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
// 1. Make sure we have at least one argument.
{ Label done;
__ test(eax, Operand(eax));
__ j(not_zero, &done, taken);
__ pop(ebx);
__ push(Immediate(Factory::undefined_value()));
__ push(ebx);
__ inc(eax);
__ bind(&done);
}
// 2. Get the function to call from the stack.
{ Label done, non_function, function;
// +1 ~ return address.
__ mov(edi, Operand(esp, eax, times_4, +1 * kPointerSize));
__ test(edi, Immediate(kSmiTagMask));
__ j(zero, &non_function, not_taken);
__ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset)); // get the map
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
__ cmp(ecx, JS_FUNCTION_TYPE);
__ j(equal, &function, taken);
// Non-function called: Clear the function to force exception.
__ bind(&non_function);
__ xor_(edi, Operand(edi));
__ jmp(&done);
// Function called: Change context eagerly to get the right global object.
__ bind(&function);
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
__ bind(&done);
}
// 3. Make sure first argument is an object; convert if necessary.
{ Label call_to_object, use_global_receiver, patch_receiver, done;
__ mov(ebx, Operand(esp, eax, times_4, 0));
__ test(ebx, Immediate(kSmiTagMask));
__ j(zero, &call_to_object);
__ cmp(ebx, Factory::null_value());
__ j(equal, &use_global_receiver);
__ cmp(ebx, Factory::undefined_value());
__ j(equal, &use_global_receiver);
__ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
__ cmp(ecx, FIRST_JS_OBJECT_TYPE);
__ j(less, &call_to_object);
__ cmp(ecx, LAST_JS_OBJECT_TYPE);
__ j(less_equal, &done);
__ bind(&call_to_object);
__ EnterInternalFrame(); // preserves eax, ebx, edi
// Store the arguments count on the stack (smi tagged).
ASSERT(kSmiTag == 0);
__ shl(eax, kSmiTagSize);
__ push(eax);
__ push(edi); // save edi across the call
__ push(ebx);
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
__ mov(Operand(ebx), eax);
__ pop(edi); // restore edi after the call
// Get the arguments count and untag it.
__ pop(eax);
__ shr(eax, kSmiTagSize);
__ LeaveInternalFrame();
__ jmp(&patch_receiver);
// Use the global receiver object from the called function as the receiver.
__ bind(&use_global_receiver);
const int kGlobalIndex =
Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
__ mov(ebx, FieldOperand(esi, kGlobalIndex));
__ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
__ bind(&patch_receiver);
__ mov(Operand(esp, eax, times_4, 0), ebx);
__ bind(&done);
}
// 4. Shift stuff one slot down the stack.
{ Label loop;
__ lea(ecx, Operand(eax, +1)); // +1 ~ copy receiver too
__ bind(&loop);
__ mov(ebx, Operand(esp, ecx, times_4, 0));
__ mov(Operand(esp, ecx, times_4, kPointerSize), ebx);
__ dec(ecx);
__ j(not_zero, &loop);
}
// 5. Remove TOS (copy of last arguments), but keep return address.
__ pop(ebx);
__ pop(ecx);
__ push(ebx);
__ dec(eax);
// 6. Check that function really was a function and get the code to
// call from the function and check that the number of expected
// arguments matches what we're providing.
{ Label invoke;
__ test(edi, Operand(edi));
__ j(not_zero, &invoke, taken);
__ xor_(ebx, Operand(ebx));
__ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
__ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
RelocInfo::CODE_TARGET);
__ bind(&invoke);
__ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
__ mov(ebx,
FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
__ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset));
__ lea(edx, FieldOperand(edx, Code::kHeaderSize));
__ cmp(eax, Operand(ebx));
__ j(not_equal, Handle<Code>(builtin(ArgumentsAdaptorTrampoline)));
}
// 7. Jump (tail-call) to the code in register edx without checking arguments.
ParameterCount expected(0);
__ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION);
}
void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
__ EnterInternalFrame();
__ push(Operand(ebp, 4 * kPointerSize)); // push this
__ push(Operand(ebp, 2 * kPointerSize)); // push arguments
__ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
if (FLAG_check_stack) {
// We need to catch preemptions right here, otherwise an unlucky preemption
// could show up as a failed apply.
ExternalReference stack_guard_limit =
ExternalReference::address_of_stack_guard_limit();
Label retry_preemption;
Label no_preemption;
__ bind(&retry_preemption);
__ mov(edi, Operand::StaticVariable(stack_guard_limit));
__ cmp(esp, Operand(edi));
__ j(above, &no_preemption, taken);
// Preemption!
// Because builtins always remove the receiver from the stack, we
// have to fake one to avoid underflowing the stack.
__ push(eax);
__ push(Immediate(Smi::FromInt(0)));
// Do call to runtime routine.
__ CallRuntime(Runtime::kStackGuard, 1);
__ pop(eax);
__ jmp(&retry_preemption);
__ bind(&no_preemption);
Label okay;
// Make ecx the space we have left.
__ mov(ecx, Operand(esp));
__ sub(ecx, Operand(edi));
// Make edx the space we need for the array when it is unrolled onto the
// stack.
__ mov(edx, Operand(eax));
__ shl(edx, kPointerSizeLog2 - kSmiTagSize);
__ cmp(ecx, Operand(edx));
__ j(greater, &okay, taken);
// Too bad: Out of stack space.
__ push(Operand(ebp, 4 * kPointerSize)); // push this
__ push(eax);
__ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION);
__ bind(&okay);
}
// Push current index and limit.
const int kLimitOffset =
StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
__ push(eax); // limit
__ push(Immediate(0)); // index
// Change context eagerly to get the right global object if
// necessary.
__ mov(edi, Operand(ebp, 4 * kPointerSize));
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
// Compute the receiver.
Label call_to_object, use_global_receiver, push_receiver;
__ mov(ebx, Operand(ebp, 3 * kPointerSize));
__ test(ebx, Immediate(kSmiTagMask));
__ j(zero, &call_to_object);
__ cmp(ebx, Factory::null_value());
__ j(equal, &use_global_receiver);
__ cmp(ebx, Factory::undefined_value());
__ j(equal, &use_global_receiver);
// If given receiver is already a JavaScript object then there's no
// reason for converting it.
__ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
__ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
__ cmp(ecx, FIRST_JS_OBJECT_TYPE);
__ j(less, &call_to_object);
__ cmp(ecx, LAST_JS_OBJECT_TYPE);
__ j(less_equal, &push_receiver);
// Convert the receiver to an object.
__ bind(&call_to_object);
__ push(ebx);
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
__ mov(ebx, Operand(eax));
__ jmp(&push_receiver);
// Use the current global receiver object as the receiver.
__ bind(&use_global_receiver);
const int kGlobalOffset =
Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
__ mov(ebx, FieldOperand(esi, kGlobalOffset));
__ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
// Push the receiver.
__ bind(&push_receiver);
__ push(ebx);
// Copy all arguments from the array to the stack.
Label entry, loop;
__ mov(eax, Operand(ebp, kIndexOffset));
__ jmp(&entry);
__ bind(&loop);
__ mov(ecx, Operand(ebp, 2 * kPointerSize)); // load arguments
__ push(ecx);
__ push(eax);
// Use inline caching to speed up access to arguments.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// Remove IC arguments from the stack and push the nth argument.
__ add(Operand(esp), Immediate(2 * kPointerSize));
__ push(eax);
// Update the index on the stack and in register eax.
__ mov(eax, Operand(ebp, kIndexOffset));
__ add(Operand(eax), Immediate(1 << kSmiTagSize));
__ mov(Operand(ebp, kIndexOffset), eax);
__ bind(&entry);
__ cmp(eax, Operand(ebp, kLimitOffset));
__ j(not_equal, &loop);
// Invoke the function.
ParameterCount actual(eax);
__ shr(eax, kSmiTagSize);
__ mov(edi, Operand(ebp, 4 * kPointerSize));
__ InvokeFunction(edi, actual, CALL_FUNCTION);
__ LeaveInternalFrame();
__ ret(3 * kPointerSize); // remove this, receiver, and arguments
}
static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
__ push(ebp);
__ mov(ebp, Operand(esp));
// Store the arguments adaptor context sentinel.
__ push(Immediate(ArgumentsAdaptorFrame::SENTINEL));
// Push the function on the stack.
__ push(edi);
// Preserve the number of arguments on the stack. Must preserve both
// eax and ebx because these registers are used when copying the
// arguments and the receiver.
ASSERT(kSmiTagSize == 1);
__ lea(ecx, Operand(eax, eax, times_1, kSmiTag));
__ push(Operand(ecx));
}
static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
// Retrieve the number of arguments from the stack.
__ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
// Leave the frame.
__ leave();
// Remove caller arguments from the stack.
ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
__ pop(ecx);
__ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
__ push(ecx);
}
void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : actual number of arguments
// -- ebx : expected number of arguments
// -- edx : code entry to call
// -----------------------------------
Label invoke, dont_adapt_arguments;
__ IncrementCounter(&Counters::arguments_adaptors, 1);
Label enough, too_few;
__ cmp(eax, Operand(ebx));
__ j(less, &too_few);
__ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
__ j(equal, &dont_adapt_arguments);
{ // Enough parameters: Actual >= expected.
__ bind(&enough);
EnterArgumentsAdaptorFrame(masm);
// Copy receiver and all expected arguments.
const int offset = StandardFrameConstants::kCallerSPOffset;
__ lea(eax, Operand(ebp, eax, times_4, offset));
__ mov(ecx, -1); // account for receiver
Label copy;
__ bind(&copy);
__ inc(ecx);
__ push(Operand(eax, 0));
__ sub(Operand(eax), Immediate(kPointerSize));
__ cmp(ecx, Operand(ebx));
__ j(less, &copy);
__ jmp(&invoke);
}
{ // Too few parameters: Actual < expected.
__ bind(&too_few);
EnterArgumentsAdaptorFrame(masm);
// Copy receiver and all actual arguments.
const int offset = StandardFrameConstants::kCallerSPOffset;
__ lea(edi, Operand(ebp, eax, times_4, offset));
__ mov(ecx, -1); // account for receiver
Label copy;
__ bind(&copy);
__ inc(ecx);
__ push(Operand(edi, 0));
__ sub(Operand(edi), Immediate(kPointerSize));
__ cmp(ecx, Operand(eax));
__ j(less, &copy);
// Fill remaining expected arguments with undefined values.
Label fill;
__ bind(&fill);
__ inc(ecx);
__ push(Immediate(Factory::undefined_value()));
__ cmp(ecx, Operand(ebx));
__ j(less, &fill);
// Restore function pointer.
__ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
}
// Call the entry point.
__ bind(&invoke);
__ call(Operand(edx));
// Leave frame and return.
LeaveArgumentsAdaptorFrame(masm);
__ ret(0);
// -------------------------------------------
// Dont adapt arguments.
// -------------------------------------------
__ bind(&dont_adapt_arguments);
__ jmp(Operand(edx));
}
static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
RegList pointer_regs,
bool convert_call_to_jmp) {
// Save the content of all general purpose registers in memory. This copy in
// memory is later pushed onto the JS expression stack for the fake JS frame
// generated and also to the C frame generated on top of that. In the JS
// frame ONLY the registers containing pointers will be pushed on the
// expression stack. This causes the GC to update these pointers so that
// they will have the correct value when returning from the debugger.
__ SaveRegistersToMemory(kJSCallerSaved);
// Enter an internal frame.
__ EnterInternalFrame();
// Store the registers containing object pointers on the expression stack to
// make sure that these are correctly updated during GC.
__ PushRegistersFromMemory(pointer_regs);
#ifdef DEBUG
__ RecordComment("// Calling from debug break to runtime - come in - over");
#endif
__ Set(eax, Immediate(0)); // no arguments
__ mov(Operand(ebx), Immediate(ExternalReference::debug_break()));
CEntryDebugBreakStub ceb;
__ CallStub(&ceb);
// Restore the register values containing object pointers from the expression
// stack in the reverse order as they where pushed.
__ PopRegistersToMemory(pointer_regs);
// Get rid of the internal frame.
__ LeaveInternalFrame();
// If this call did not replace a call but patched other code then there will
// be an unwanted return address left on the stack. Here we get rid of that.
if (convert_call_to_jmp) {
__ pop(eax);
}
// Finally restore all registers.
__ RestoreRegistersFromMemory(kJSCallerSaved);
// Now that the break point has been handled, resume normal execution by
// jumping to the target address intended by the caller and that was
// overwritten by the address of DebugBreakXXX.
ExternalReference after_break_target =
ExternalReference(Debug_Address::AfterBreakTarget());
__ jmp(Operand::StaticVariable(after_break_target));
}
void Builtins::Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
// Register state for IC load call (from ic-ia32.cc).
// ----------- S t a t e -------------
// -- ecx : name
// -----------------------------------
Generate_DebugBreakCallHelper(masm, ecx.bit(), false);
}
void Builtins::Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
// REgister state for IC store call (from ic-ia32.cc).
// ----------- S t a t e -------------
// -- eax : value
// -- ecx : name
// -----------------------------------
Generate_DebugBreakCallHelper(masm, eax.bit() | ecx.bit(), false);
}
void Builtins::Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
// Register state for keyed IC load call (from ic-ia32.cc).
// ----------- S t a t e -------------
// No registers used on entry.
// -----------------------------------
Generate_DebugBreakCallHelper(masm, 0, false);
}
void Builtins::Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
// Register state for keyed IC load call (from ic-ia32.cc).
// ----------- S t a t e -------------
// -- eax : value
// -----------------------------------
// Register eax contains an object that needs to be pushed on the
// expression stack of the fake JS frame.
Generate_DebugBreakCallHelper(masm, eax.bit(), false);
}
void Builtins::Generate_CallIC_DebugBreak(MacroAssembler* masm) {
// Register state for keyed IC call call (from ic-ia32.cc)
// ----------- S t a t e -------------
// -- eax: number of arguments
// -----------------------------------
// The number of arguments in eax is not smi encoded.
Generate_DebugBreakCallHelper(masm, 0, false);
}
void Builtins::Generate_ConstructCall_DebugBreak(MacroAssembler* masm) {
// Register state just before return from JS function (from codegen-ia32.cc).
// eax is the actual number of arguments not encoded as a smi see comment
// above IC call.
// ----------- S t a t e -------------
// -- eax: number of arguments
// -----------------------------------
// The number of arguments in eax is not smi encoded.
Generate_DebugBreakCallHelper(masm, 0, false);
}
void Builtins::Generate_Return_DebugBreak(MacroAssembler* masm) {
// Register state just before return from JS function (from codegen-ia32.cc).
// ----------- S t a t e -------------
// -- eax: return value
// -----------------------------------
Generate_DebugBreakCallHelper(masm, eax.bit(), true);
}
void Builtins::Generate_Return_DebugBreakEntry(MacroAssembler* masm) {
// OK to clobber ebx as we are returning from a JS function in the code
// generated by Ia32CodeGenerator::ExitJSFrame.
ExternalReference debug_break_return =
ExternalReference(Debug_Address::DebugBreakReturn());
__ mov(ebx, Operand::StaticVariable(debug_break_return));
__ add(Operand(ebx), Immediate(Code::kHeaderSize - kHeapObjectTag));
__ jmp(Operand(ebx));
}
void Builtins::Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) {
// Register state for stub CallFunction (from CallFunctionStub in ic-ia32.cc).
// ----------- S t a t e -------------
// No registers used on entry.
// -----------------------------------
Generate_DebugBreakCallHelper(masm, 0, false);
}
#undef __
} } // namespace v8::internal

View File

@ -1,714 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#include "v8.h"
#include "api.h"
#include "bootstrapper.h"
#include "builtins.h"
#include "ic-inl.h"
namespace v8 { namespace internal {
// ----------------------------------------------------------------------------
// Support macros for defining builtins in C.
// ----------------------------------------------------------------------------
//
// A builtin function is defined by writing:
//
// BUILTIN(name) {
// ...
// }
// BUILTIN_END
//
// In the body of the builtin function, the variable 'receiver' is visible.
// The arguments can be accessed through:
//
// BUILTIN_ARG(0): Receiver (also available as 'receiver')
// BUILTIN_ARG(1): First argument
// ...
// BUILTIN_ARG(n): Last argument
//
// and they evaluate to undefined values if too few arguments were
// passed to the builtin function invocation.
//
// __argc__ is the number of arguments including the receiver.
// ----------------------------------------------------------------------------
// TODO(1238487): We should consider passing whether or not the
// builtin was invoked as a constructor as part of the
// arguments. Maybe we also want to pass the called function?
#define BUILTIN(name) \
static Object* Builtin_##name(int __argc__, Object** __argv__) { \
Handle<Object> receiver(&__argv__[0]);
// Use an inline function to avoid evaluating the index (n) more than
// once in the BUILTIN_ARG macro.
static inline Object* __builtin_arg__(int n, int argc, Object** argv) {
ASSERT(n >= 0);
return (argc > n) ? argv[-n] : Heap::undefined_value();
}
// NOTE: Argument 0 is the receiver. The first 'real' argument is
// argument 1 - BUILTIN_ARG(1).
#define BUILTIN_ARG(n) (__builtin_arg__(n, __argc__, __argv__))
#define BUILTIN_END \
return Heap::undefined_value(); \
}
// TODO(1238487): Get rid of this function that determines if the
// builtin is called as a constructor. This may be a somewhat slow
// operation due to the stack frame iteration.
static inline bool CalledAsConstructor() {
StackFrameIterator it;
ASSERT(it.frame()->is_exit());
it.Advance();
StackFrame* frame = it.frame();
return frame->is_construct();
}
// ----------------------------------------------------------------------------
Handle<Code> Builtins::GetCode(JavaScript id, bool* resolved) {
Code* code = Builtins::builtin(Builtins::Illegal);
*resolved = false;
if (Top::context() != NULL) {
Object* object = Top::builtins()->javascript_builtin(id);
if (object->IsJSFunction()) {
Handle<JSFunction> function(JSFunction::cast(object));
// Make sure the number of parameters match the formal parameter count.
ASSERT(function->shared()->formal_parameter_count() ==
Builtins::GetArgumentsCount(id));
if (function->is_compiled() || CompileLazy(function, CLEAR_EXCEPTION)) {
code = function->code();
*resolved = true;
}
}
}
return Handle<Code>(code);
}
BUILTIN(Illegal) {
UNREACHABLE();
}
BUILTIN_END
BUILTIN(EmptyFunction) {
}
BUILTIN_END
BUILTIN(ArrayCode) {
JSArray* array;
if (CalledAsConstructor()) {
array = JSArray::cast(*receiver);
} else {
// Allocate the JS Array
JSFunction* constructor =
Top::context()->global_context()->array_function();
Object* obj = Heap::AllocateJSObject(constructor);
if (obj->IsFailure()) return obj;
array = JSArray::cast(obj);
}
// 'array' now contains the JSArray we should initialize.
// Optimize the case where there is one argument and the argument is a
// small smi.
if (__argc__ == 2) {
Object* obj = BUILTIN_ARG(1);
if (obj->IsSmi()) {
int len = Smi::cast(obj)->value();
if (len >= 0 && len < JSObject::kMaxFastElementsLength) {
Object* obj = Heap::AllocateFixedArrayWithHoles(len);
if (obj->IsFailure()) return obj;
array->SetContent(FixedArray::cast(obj));
return array;
}
}
// Take the argument as the length.
obj = array->Initialize(0);
if (obj->IsFailure()) return obj;
if (__argc__ == 2) return array->SetElementsLength(BUILTIN_ARG(1));
}
// Optimize the case where there are no parameters passed.
if (__argc__ == 1) return array->Initialize(4);
// Take the arguments as elements.
int number_of_elements = __argc__ - 1;
Smi* len = Smi::FromInt(number_of_elements);
Object* obj = Heap::AllocateFixedArrayWithHoles(len->value());
if (obj->IsFailure()) return obj;
FixedArray* elms = FixedArray::cast(obj);
WriteBarrierMode mode = elms->GetWriteBarrierMode();
// Fill in the content
for (int index = 0; index < number_of_elements; index++) {
elms->set(index, BUILTIN_ARG(index+1), mode);
}
// Set length and elements on the array.
array->set_elements(FixedArray::cast(obj));
array->set_length(len, SKIP_WRITE_BARRIER);
return array;
}
BUILTIN_END
BUILTIN(ArrayPush) {
JSArray* array = JSArray::cast(*receiver);
ASSERT(array->HasFastElements());
// Make sure we have space for the elements.
int len = Smi::cast(array->length())->value();
// Set new length.
int new_length = len + __argc__ - 1;
FixedArray* elms = FixedArray::cast(array->elements());
if (new_length <= elms->length()) {
// Backing storage has extra space for the provided values.
for (int index = 0; index < __argc__ - 1; index++) {
elms->set(index + len, BUILTIN_ARG(index+1));
}
} else {
// New backing storage is needed.
int capacity = new_length + (new_length >> 1) + 16;
Object* obj = Heap::AllocateFixedArrayWithHoles(capacity);
if (obj->IsFailure()) return obj;
FixedArray* new_elms = FixedArray::cast(obj);
WriteBarrierMode mode = new_elms->GetWriteBarrierMode();
// Fill out the new array with old elements.
for (int i = 0; i < len; i++) new_elms->set(i, elms->get(i), mode);
// Add the provided values.
for (int index = 0; index < __argc__ - 1; index++) {
new_elms->set(index + len, BUILTIN_ARG(index+1), mode);
}
// Set the new backing storage.
array->set_elements(new_elms);
}
// Set the length.
array->set_length(Smi::FromInt(new_length), SKIP_WRITE_BARRIER);
return array->length();
}
BUILTIN_END
BUILTIN(ArrayPop) {
JSArray* array = JSArray::cast(*receiver);
ASSERT(array->HasFastElements());
Object* undefined = Heap::undefined_value();
int len = Smi::cast(array->length())->value();
if (len == 0) return undefined;
// Get top element
FixedArray* elms = FixedArray::cast(array->elements());
Object* top = elms->get(len - 1);
// Set the length.
array->set_length(Smi::FromInt(len - 1), SKIP_WRITE_BARRIER);
if (!top->IsTheHole()) {
// Delete the top element.
elms->set_the_hole(len - 1);
return top;
}
// Remember to check the prototype chain.
JSFunction* array_function =
Top::context()->global_context()->array_function();
JSObject* prototype = JSObject::cast(array_function->prototype());
top = prototype->GetElement(len - 1);
return top;
}
BUILTIN_END
// -----------------------------------------------------------------------------
//
// Returns the holder JSObject if the function can legally be called
// with this receiver. Returns Heap::null_value() if the call is
// illegal. Any arguments that don't fit the expected type is
// overwritten with undefined. Arguments that do fit the expected
// type is overwritten with the object in the prototype chain that
// actually has that type.
static inline Object* TypeCheck(int argc,
Object** argv,
FunctionTemplateInfo* info) {
Object* recv = argv[0];
Object* sig_obj = info->signature();
if (sig_obj->IsUndefined()) return recv;
SignatureInfo* sig = SignatureInfo::cast(sig_obj);
// If necessary, check the receiver
Object* recv_type = sig->receiver();
Object* holder = recv;
if (!recv_type->IsUndefined()) {
for (; holder != Heap::null_value(); holder = holder->GetPrototype()) {
if (holder->IsInstanceOf(FunctionTemplateInfo::cast(recv_type))) {
break;
}
}
if (holder == Heap::null_value()) return holder;
}
Object* args_obj = sig->args();
// If there is no argument signature we're done
if (args_obj->IsUndefined()) return holder;
FixedArray* args = FixedArray::cast(args_obj);
int length = args->length();
if (argc <= length) length = argc - 1;
for (int i = 0; i < length; i++) {
Object* argtype = args->get(i);
if (argtype->IsUndefined()) continue;
Object** arg = &argv[-1 - i];
Object* current = *arg;
for (; current != Heap::null_value(); current = current->GetPrototype()) {
if (current->IsInstanceOf(FunctionTemplateInfo::cast(argtype))) {
*arg = current;
break;
}
}
if (current == Heap::null_value()) *arg = Heap::undefined_value();
}
return holder;
}
BUILTIN(HandleApiCall) {
HandleScope scope;
bool is_construct = CalledAsConstructor();
// TODO(1238487): This is not nice. We need to get rid of this
// kludgy behavior and start handling API calls in a more direct
// way - maybe compile specialized stubs lazily?.
Handle<JSFunction> function =
Handle<JSFunction>(JSFunction::cast(Builtins::builtin_passed_function));
if (is_construct) {
Handle<FunctionTemplateInfo> desc =
Handle<FunctionTemplateInfo>(
FunctionTemplateInfo::cast(function->shared()->function_data()));
bool pending_exception = false;
Factory::ConfigureInstance(desc, Handle<JSObject>::cast(receiver),
&pending_exception);
ASSERT(Top::has_pending_exception() == pending_exception);
if (pending_exception) return Failure::Exception();
}
FunctionTemplateInfo* fun_data =
FunctionTemplateInfo::cast(function->shared()->function_data());
Object* raw_holder = TypeCheck(__argc__, __argv__, fun_data);
if (raw_holder->IsNull()) {
// This function cannot be called with the given receiver. Abort!
Handle<Object> obj =
Factory::NewTypeError("illegal_invocation", HandleVector(&function, 1));
return Top::Throw(*obj);
}
Object* raw_call_data = fun_data->call_code();
if (!raw_call_data->IsUndefined()) {
CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
Object* callback_obj = call_data->callback();
v8::InvocationCallback callback =
v8::ToCData<v8::InvocationCallback>(callback_obj);
Object* data_obj = call_data->data();
Object* result;
v8::Local<v8::Object> self =
v8::Utils::ToLocal(Handle<JSObject>::cast(receiver));
Handle<Object> data_handle(data_obj);
v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
ASSERT(raw_holder->IsJSObject());
v8::Local<v8::Function> callee = v8::Utils::ToLocal(function);
Handle<JSObject> holder_handle(JSObject::cast(raw_holder));
v8::Local<v8::Object> holder = v8::Utils::ToLocal(holder_handle);
LOG(ApiObjectAccess("call", JSObject::cast(*receiver)));
v8::Arguments args = v8::ImplementationUtilities::NewArguments(
data,
holder,
callee,
is_construct,
reinterpret_cast<void**>(__argv__ - 1),
__argc__ - 1);
v8::Handle<v8::Value> value;
{
// Leaving JavaScript.
VMState state(OTHER);
value = callback(args);
}
if (value.IsEmpty()) {
result = Heap::undefined_value();
} else {
result = *reinterpret_cast<Object**>(*value);
}
RETURN_IF_SCHEDULED_EXCEPTION();
if (!is_construct || result->IsJSObject()) return result;
}
return *receiver;
}
BUILTIN_END
// Handle calls to non-function objects created through the API that
// support calls.
BUILTIN(HandleApiCallAsFunction) {
// Non-functions are never called as constructors.
ASSERT(!CalledAsConstructor());
// Get the object called.
JSObject* obj = JSObject::cast(*receiver);
// Get the invocation callback from the function descriptor that was
// used to create the called object.
ASSERT(obj->map()->has_instance_call_handler());
JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
Object* template_info = constructor->shared()->function_data();
Object* handler =
FunctionTemplateInfo::cast(template_info)->instance_call_handler();
ASSERT(!handler->IsUndefined());
CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
Object* callback_obj = call_data->callback();
v8::InvocationCallback callback =
v8::ToCData<v8::InvocationCallback>(callback_obj);
// Get the data for the call and perform the callback.
Object* data_obj = call_data->data();
Object* result;
{ HandleScope scope;
v8::Local<v8::Object> self =
v8::Utils::ToLocal(Handle<JSObject>::cast(receiver));
Handle<Object> data_handle(data_obj);
v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
Handle<JSFunction> callee_handle(constructor);
v8::Local<v8::Function> callee = v8::Utils::ToLocal(callee_handle);
LOG(ApiObjectAccess("call non-function", JSObject::cast(*receiver)));
v8::Arguments args = v8::ImplementationUtilities::NewArguments(
data,
self,
callee,
false,
reinterpret_cast<void**>(__argv__ - 1),
__argc__ - 1);
v8::Handle<v8::Value> value;
{
// Leaving JavaScript.
VMState state(OTHER);
value = callback(args);
}
if (value.IsEmpty()) {
result = Heap::undefined_value();
} else {
result = *reinterpret_cast<Object**>(*value);
}
}
// Check for exceptions and return result.
RETURN_IF_SCHEDULED_EXCEPTION();
return result;
}
BUILTIN_END
// TODO(1238487): This is a nasty hack. We need to improve the way we
// call builtins considerable to get rid of this and the hairy macros
// in builtins.cc.
Object* Builtins::builtin_passed_function;
static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) {
LoadIC::GenerateArrayLength(masm);
}
static void Generate_LoadIC_ShortStringLength(MacroAssembler* masm) {
LoadIC::GenerateShortStringLength(masm);
}
static void Generate_LoadIC_MediumStringLength(MacroAssembler* masm) {
LoadIC::GenerateMediumStringLength(masm);
}
static void Generate_LoadIC_LongStringLength(MacroAssembler* masm) {
LoadIC::GenerateLongStringLength(masm);
}
static void Generate_LoadIC_FunctionPrototype(MacroAssembler* masm) {
LoadIC::GenerateFunctionPrototype(masm);
}
static void Generate_LoadIC_Initialize(MacroAssembler* masm) {
LoadIC::GenerateInitialize(masm);
}
static void Generate_LoadIC_PreMonomorphic(MacroAssembler* masm) {
LoadIC::GeneratePreMonomorphic(masm);
}
static void Generate_LoadIC_Miss(MacroAssembler* masm) {
LoadIC::GenerateMiss(masm);
}
static void Generate_LoadIC_Megamorphic(MacroAssembler* masm) {
LoadIC::GenerateMegamorphic(masm);
}
static void Generate_LoadIC_Normal(MacroAssembler* masm) {
LoadIC::GenerateNormal(masm);
}
static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
KeyedLoadIC::GenerateInitialize(masm);
}
static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
KeyedLoadIC::GenerateMiss(masm);
}
static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
KeyedLoadIC::GenerateGeneric(masm);
}
static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
KeyedLoadIC::GeneratePreMonomorphic(masm);
}
static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
StoreIC::GenerateInitialize(masm);
}
static void Generate_StoreIC_Miss(MacroAssembler* masm) {
StoreIC::GenerateMiss(masm);
}
static void Generate_StoreIC_ExtendStorage(MacroAssembler* masm) {
StoreIC::GenerateExtendStorage(masm);
}
static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) {
StoreIC::GenerateMegamorphic(masm);
}
static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
KeyedStoreIC::GenerateGeneric(masm);
}
static void Generate_KeyedStoreIC_ExtendStorage(MacroAssembler* masm) {
KeyedStoreIC::GenerateExtendStorage(masm);
}
static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
KeyedStoreIC::GenerateMiss(masm);
}
static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
KeyedStoreIC::GenerateInitialize(masm);
}
Object* Builtins::builtins_[builtin_count] = { NULL, };
const char* Builtins::names_[builtin_count] = { NULL, };
#define DEF_ENUM_C(name) FUNCTION_ADDR(Builtin_##name),
Address Builtins::c_functions_[cfunction_count] = {
BUILTIN_LIST_C(DEF_ENUM_C)
};
#undef DEF_ENUM_C
#define DEF_JS_NAME(name, ignore) #name,
#define DEF_JS_ARGC(ignore, argc) argc,
const char* Builtins::javascript_names_[id_count] = {
BUILTINS_LIST_JS(DEF_JS_NAME)
};
int Builtins::javascript_argc_[id_count] = {
BUILTINS_LIST_JS(DEF_JS_ARGC)
};
#undef DEF_JS_NAME
#undef DEF_JS_ARGC
static bool is_initialized = false;
void Builtins::Setup(bool create_heap_objects) {
ASSERT(!is_initialized);
// Create a scope for the handles in the builtins.
HandleScope scope;
struct BuiltinDesc {
byte* generator;
byte* c_code;
const char* s_name; // name is only used for generating log information.
int name;
Code::Flags flags;
};
#define DEF_FUNCTION_PTR_C(name) \
{ FUNCTION_ADDR(Generate_Adaptor), \
FUNCTION_ADDR(Builtin_##name), \
#name, \
c_##name, \
Code::ComputeFlags(Code::BUILTIN) \
},
#define DEF_FUNCTION_PTR_A(name, kind, state) \
{ FUNCTION_ADDR(Generate_##name), \
NULL, \
#name, \
name, \
Code::ComputeFlags(Code::kind, state) \
},
// Define array of pointers to generators and C builtin functions.
static BuiltinDesc functions[] = {
BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
// Terminator:
{ NULL, NULL, NULL, builtin_count, static_cast<Code::Flags>(0) }
};
#undef DEF_FUNCTION_PTR_C
#undef DEF_FUNCTION_PTR_A
// For now we generate builtin adaptor code into a stack-allocated
// buffer, before copying it into individual code objects.
byte buffer[4*KB];
// Traverse the list of builtins and generate an adaptor in a
// separate code object for each one.
for (int i = 0; i < builtin_count; i++) {
if (create_heap_objects) {
MacroAssembler masm(buffer, sizeof buffer);
// Generate the code/adaptor.
typedef void (*Generator)(MacroAssembler*, int);
Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
// We pass all arguments to the generator, but it may not use all of
// them. This works because the first arguments are on top of the
// stack.
g(&masm, functions[i].name);
// Move the code into the object heap.
CodeDesc desc;
masm.GetCode(&desc);
Code::Flags flags = functions[i].flags;
Object* code = Heap::CreateCode(desc, NULL, flags);
if (code->IsFailure()) {
if (code->IsRetryAfterGC()) {
CHECK(Heap::CollectGarbage(Failure::cast(code)->requested(),
Failure::cast(code)->allocation_space()));
code = Heap::CreateCode(desc, NULL, flags);
}
if (code->IsFailure()) {
v8::internal::V8::FatalProcessOutOfMemory("CreateCode");
}
}
// Add any unresolved jumps or calls to the fixup list in the
// bootstrapper.
Bootstrapper::AddFixup(Code::cast(code), &masm);
// Log the event and add the code to the builtins array.
LOG(CodeCreateEvent("Builtin", Code::cast(code), functions[i].s_name));
builtins_[i] = code;
#ifdef DEBUG
if (FLAG_print_builtin_code) {
PrintF("Builtin: %s\n", functions[i].s_name);
code->Print();
PrintF("\n");
}
#endif
} else {
// Deserializing. The values will be filled in during IterateBuiltins.
builtins_[i] = NULL;
}
names_[i] = functions[i].s_name;
}
// Mark as initialized.
is_initialized = true;
}
void Builtins::TearDown() {
is_initialized = false;
}
void Builtins::IterateBuiltins(ObjectVisitor* v) {
v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
}
const char* Builtins::Lookup(byte* pc) {
if (is_initialized) { // may be called during initialization (disassembler!)
for (int i = 0; i < builtin_count; i++) {
Code* entry = Code::cast(builtins_[i]);
if (entry->contains(pc)) {
return names_[i];
}
}
}
return NULL;
}
} } // namespace v8::internal

View File

@ -1,227 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#ifndef V8_BUILTINS_H_
#define V8_BUILTINS_H_
namespace v8 { namespace internal {
// Define list of builtins implemented in C.
#define BUILTIN_LIST_C(V) \
V(Illegal) \
\
V(EmptyFunction) \
\
V(ArrayCode) \
\
V(ArrayPush) \
V(ArrayPop) \
\
V(HandleApiCall) \
V(HandleApiCallAsFunction)
// Define list of builtins implemented in assembly.
#define BUILTIN_LIST_A(V) \
V(ArgumentsAdaptorTrampoline, BUILTIN, UNINITIALIZED) \
V(JSConstructCall, BUILTIN, UNINITIALIZED) \
V(JSEntryTrampoline, BUILTIN, UNINITIALIZED) \
V(JSConstructEntryTrampoline, BUILTIN, UNINITIALIZED) \
\
V(Return_DebugBreak, BUILTIN, DEBUG_BREAK) \
V(Return_DebugBreakEntry, BUILTIN, DEBUG_BREAK) \
V(ConstructCall_DebugBreak, BUILTIN, DEBUG_BREAK) \
V(StubNoRegisters_DebugBreak, BUILTIN, DEBUG_BREAK) \
\
V(LoadIC_Miss, BUILTIN, UNINITIALIZED) \
V(KeyedLoadIC_Miss, BUILTIN, UNINITIALIZED) \
V(StoreIC_Miss, BUILTIN, UNINITIALIZED) \
V(KeyedStoreIC_Miss, BUILTIN, UNINITIALIZED) \
\
V(StoreIC_ExtendStorage, BUILTIN, UNINITIALIZED) \
V(KeyedStoreIC_ExtendStorage, BUILTIN, UNINITIALIZED) \
\
V(LoadIC_Initialize, LOAD_IC, UNINITIALIZED) \
V(LoadIC_PreMonomorphic, LOAD_IC, PREMONOMORPHIC) \
V(LoadIC_Normal, LOAD_IC, MONOMORPHIC) \
V(LoadIC_ArrayLength, LOAD_IC, MONOMORPHIC) \
V(LoadIC_ShortStringLength, LOAD_IC, MONOMORPHIC) \
V(LoadIC_MediumStringLength, LOAD_IC, MONOMORPHIC) \
V(LoadIC_LongStringLength, LOAD_IC, MONOMORPHIC) \
V(LoadIC_FunctionPrototype, LOAD_IC, MONOMORPHIC) \
V(LoadIC_Megamorphic, LOAD_IC, MEGAMORPHIC) \
V(LoadIC_DebugBreak, LOAD_IC, DEBUG_BREAK) \
\
V(KeyedLoadIC_Initialize, KEYED_LOAD_IC, UNINITIALIZED) \
V(KeyedLoadIC_PreMonomorphic, KEYED_LOAD_IC, PREMONOMORPHIC) \
V(KeyedLoadIC_Generic, KEYED_LOAD_IC, MEGAMORPHIC) \
V(KeyedLoadIC_DebugBreak, KEYED_LOAD_IC, DEBUG_BREAK) \
\
V(StoreIC_Initialize, STORE_IC, UNINITIALIZED) \
V(StoreIC_Megamorphic, STORE_IC, MEGAMORPHIC) \
V(StoreIC_DebugBreak, STORE_IC, DEBUG_BREAK) \
\
V(KeyedStoreIC_Initialize, KEYED_STORE_IC, UNINITIALIZED) \
V(KeyedStoreIC_Generic, KEYED_STORE_IC, MEGAMORPHIC) \
V(KeyedStoreIC_DebugBreak, KEYED_STORE_IC, DEBUG_BREAK) \
\
/* Uses KeyedLoadIC_Initialize; must be after in list. */ \
V(FunctionCall, BUILTIN, UNINITIALIZED) \
V(FunctionApply, BUILTIN, UNINITIALIZED)
// Define list of builtins implemented in JavaScript.
#define BUILTINS_LIST_JS(V) \
V(EQUALS, 1) \
V(STRICT_EQUALS, 1) \
V(COMPARE, 2) \
V(ADD, 1) \
V(SUB, 1) \
V(MUL, 1) \
V(DIV, 1) \
V(MOD, 1) \
V(INC, 0) \
V(DEC, 0) \
V(BIT_OR, 1) \
V(BIT_AND, 1) \
V(BIT_XOR, 1) \
V(UNARY_MINUS, 0) \
V(BIT_NOT, 0) \
V(SHL, 1) \
V(SAR, 1) \
V(SHR, 1) \
V(DELETE, 1) \
V(IN, 1) \
V(INSTANCE_OF, 1) \
V(GET_KEYS, 0) \
V(FILTER_KEY, 1) \
V(CALL_NON_FUNCTION, 0) \
V(TO_OBJECT, 0) \
V(TO_NUMBER, 0) \
V(TO_STRING, 0) \
V(APPLY_PREPARE, 1) \
V(APPLY_OVERFLOW, 1)
class ObjectVisitor;
class Builtins : public AllStatic {
public:
// Generate all builtin code objects. Should be called once during
// VM initialization.
static void Setup(bool create_heap_objects);
static void TearDown();
// Garbage collection support.
static void IterateBuiltins(ObjectVisitor* v);
// Disassembler support.
static const char* Lookup(byte* pc);
enum Name {
#define DEF_ENUM_C(name) name,
#define DEF_ENUM_A(name, kind, state) name,
BUILTIN_LIST_C(DEF_ENUM_C)
BUILTIN_LIST_A(DEF_ENUM_A)
#undef DEF_ENUM_C
#undef DEF_ENUM_A
builtin_count
};
enum CFunctionId {
#define DEF_ENUM_C(name) c_##name,
BUILTIN_LIST_C(DEF_ENUM_C)
#undef DEF_ENUM_C
cfunction_count
};
enum JavaScript {
#define DEF_ENUM(name, ignore) name,
BUILTINS_LIST_JS(DEF_ENUM)
#undef DEF_ENUM
id_count
};
static Code* builtin(Name name) {
// Code::cast cannot be used here since we access builtins
// during the marking phase of mark sweep. See IC::Clear.
return reinterpret_cast<Code*>(builtins_[name]);
}
static Address builtin_address(Name name) {
return reinterpret_cast<Address>(&builtins_[name]);
}
static Address c_function_address(CFunctionId id) {
return c_functions_[id];
}
static const char* GetName(JavaScript id) { return javascript_names_[id]; }
static int GetArgumentsCount(JavaScript id) { return javascript_argc_[id]; }
static Handle<Code> GetCode(JavaScript id, bool* resolved);
static int NumberOfJavaScriptBuiltins() { return id_count; }
// Called from stub-cache.cc.
static void Generate_CallIC_DebugBreak(MacroAssembler* masm);
static Object* builtin_passed_function;
private:
// The external C++ functions called from the code.
static Address c_functions_[cfunction_count];
// Note: These are always Code objects, but to conform with
// IterateBuiltins() above which assumes Object**'s for the callback
// function f, we use an Object* array here.
static Object* builtins_[builtin_count];
static const char* names_[builtin_count];
static const char* javascript_names_[id_count];
static int javascript_argc_[id_count];
static void Generate_Adaptor(MacroAssembler* masm, CFunctionId id);
static void Generate_JSConstructCall(MacroAssembler* masm);
static void Generate_JSEntryTrampoline(MacroAssembler* masm);
static void Generate_JSConstructEntryTrampoline(MacroAssembler* masm);
static void Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm);
static void Generate_FunctionCall(MacroAssembler* masm);
static void Generate_FunctionApply(MacroAssembler* masm);
static void Generate_LoadIC_DebugBreak(MacroAssembler* masm);
static void Generate_StoreIC_DebugBreak(MacroAssembler* masm);
static void Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm);
static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm);
static void Generate_ConstructCall_DebugBreak(MacroAssembler* masm);
static void Generate_Return_DebugBreak(MacroAssembler* masm);
static void Generate_Return_DebugBreakEntry(MacroAssembler* masm);
static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm);
};
} } // namespace v8::internal
#endif // V8_BUILTINS_H_

View File

@ -1,64 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#ifndef V8_CHAR_PREDICATES_INL_H_
#define V8_CHAR_PREDICATES_INL_H_
#include "char-predicates.h"
namespace v8 { namespace internal {
inline bool IsCarriageReturn(uc32 c) {
return c == 0x000D;
}
inline bool IsLineFeed(uc32 c) {
return c == 0x000A;
}
inline bool IsDecimalDigit(uc32 c) {
// ECMA-262, 3rd, 7.8.3 (p 16)
return
'0' <= c && c <= '9';
}
inline bool IsHexDigit(uc32 c) {
// ECMA-262, 3rd, 7.6 (p 15)
return
('0' <= c && c <= '9') ||
('A' <= c && c <= 'F') ||
('a' <= c && c <= 'f');
}
} } // namespace v8::internal
#endif // V8_CHAR_PREDICATES_INL_H_

View File

@ -1,62 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#ifndef V8_CHAR_PREDICATES_H_
#define V8_CHAR_PREDICATES_H_
namespace v8 { namespace internal {
// Unicode character predicates as defined by ECMA-262, 3rd,
// used for lexical analysis.
inline bool IsCarriageReturn(uc32 c);
inline bool IsLineFeed(uc32 c);
inline bool IsDecimalDigit(uc32 c);
inline bool IsHexDigit(uc32 c);
struct IdentifierStart {
static inline bool Is(uc32 c) {
switch (c) {
case '$': case '_': case '\\': return true;
default: return unibrow::Letter::Is(c);
}
}
};
struct IdentifierPart {
static inline bool Is(uc32 c) {
return IdentifierStart::Is(c)
|| unibrow::Number::Is(c)
|| unibrow::CombiningMark::Is(c)
|| unibrow::ConnectorPunctuation::Is(c);
}
};
} } // namespace v8::internal
#endif // V8_CHAR_PREDICATES_H_

View File

@ -1,100 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#include <stdarg.h>
#include "v8.h"
#include "platform.h"
#include "top.h"
using namespace v8::internal;
static int fatal_error_handler_nesting_depth = 0;
// Contains protection against recursive calls (faults while handling faults).
extern "C" void V8_Fatal(const char* file, int line, const char* format, ...) {
fatal_error_handler_nesting_depth++;
// First time we try to print an error message
if (fatal_error_handler_nesting_depth < 2) {
OS::PrintError("\n\n#\n# Fatal error in %s, line %d\n# ", file, line);
va_list arguments;
va_start(arguments, format);
OS::VPrintError(format, arguments);
va_end(arguments);
OS::PrintError("\n#\n\n");
}
// First two times we may try to print a stack dump.
if (fatal_error_handler_nesting_depth < 3) {
if (FLAG_stack_trace_on_abort) {
// Call this one twice on double fault
Top::PrintStack();
}
}
OS::Abort();
}
void CheckEqualsHelper(const char* file,
int line,
const char* expected_source,
v8::Handle<v8::Value> expected,
const char* value_source,
v8::Handle<v8::Value> value) {
if (!expected->Equals(value)) {
v8::String::Utf8Value value_str(value);
v8::String::Utf8Value expected_str(expected);
V8_Fatal(file, line,
"CHECK_EQ(%s, %s) failed\n# Expected: %s\n# Found: %s",
expected_source, value_source, *expected_str, *value_str);
}
}
void CheckNonEqualsHelper(const char* file,
int line,
const char* unexpected_source,
v8::Handle<v8::Value> unexpected,
const char* value_source,
v8::Handle<v8::Value> value) {
if (unexpected->Equals(value)) {
v8::String::Utf8Value value_str(value);
V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n# Value: %s",
unexpected_source, value_source, *value_str);
}
}
void API_Fatal(const char* location, const char* format, ...) {
OS::PrintError("\n#\n# Fatal error in %s\n# ", location);
va_list arguments;
va_start(arguments, format);
OS::VPrintError(format, arguments);
va_end(arguments);
OS::PrintError("\n#\n\n");
OS::Abort();
}

View File

@ -1,259 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#ifndef V8_CHECKS_H_
#define V8_CHECKS_H_
#include <string.h>
#include "flags.h"
extern "C" void V8_Fatal(const char* file, int line, const char* format, ...);
void API_Fatal(const char* location, const char* format, ...);
// The FATAL, UNREACHABLE and UNIMPLEMENTED macros are useful during
// development, but they should not be relied on in the final product.
#ifdef DEBUG
#define FATAL(msg) \
V8_Fatal(__FILE__, __LINE__, "%s", (msg))
#define UNIMPLEMENTED() \
V8_Fatal(__FILE__, __LINE__, "unimplemented code")
#define UNREACHABLE() \
V8_Fatal(__FILE__, __LINE__, "unreachable code")
#else
#define FATAL(msg) \
V8_Fatal("", 0, "%s", (msg))
#define UNIMPLEMENTED() \
V8_Fatal("", 0, "unimplemented code")
#define UNREACHABLE() ((void) 0)
#endif
// Used by the CHECK macro -- should not be called directly.
static inline void CheckHelper(const char* file,
int line,
const char* source,
bool condition) {
if (!condition)
V8_Fatal(file, line, "CHECK(%s) failed", source);
}
// The CHECK macro checks that the given condition is true; if not, it
// prints a message to stderr and aborts.
#define CHECK(condition) CheckHelper(__FILE__, __LINE__, #condition, condition)
// Helper function used by the CHECK_EQ function when given int
// arguments. Should not be called directly.
static inline void CheckEqualsHelper(const char* file, int line,
const char* expected_source, int expected,
const char* value_source, int value) {
if (expected != value) {
V8_Fatal(file, line,
"CHECK_EQ(%s, %s) failed\n# Expected: %i\n# Found: %i",
expected_source, value_source, expected, value);
}
}
// Helper function used by the CHECK_NE function when given int
// arguments. Should not be called directly.
static inline void CheckNonEqualsHelper(const char* file,
int line,
const char* unexpected_source,
int unexpected,
const char* value_source,
int value) {
if (unexpected == value) {
V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n# Value: %i",
unexpected_source, value_source, value);
}
}
// Helper function used by the CHECK function when given string
// arguments. Should not be called directly.
static inline void CheckEqualsHelper(const char* file,
int line,
const char* expected_source,
const char* expected,
const char* value_source,
const char* value) {
if (strcmp(expected, value) != 0) {
V8_Fatal(file, line,
"CHECK_EQ(%s, %s) failed\n# Expected: %s\n# Found: %s",
expected_source, value_source, expected, value);
}
}
static inline void CheckNonEqualsHelper(const char* file,
int line,
const char* expected_source,
const char* expected,
const char* value_source,
const char* value) {
if (expected == value ||
(expected != NULL && value != NULL && strcmp(expected, value) == 0)) {
V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n# Value: %s",
expected_source, value_source, value);
}
}
// Helper function used by the CHECK function when given pointer
// arguments. Should not be called directly.
static inline void CheckEqualsHelper(const char* file,
int line,
const char* expected_source,
void* expected,
const char* value_source,
void* value) {
if (expected != value) {
V8_Fatal(file, line,
"CHECK_EQ(%s, %s) failed\n# Expected: %i\n# Found: %i",
expected_source, value_source,
reinterpret_cast<int>(expected), reinterpret_cast<int>(value));
}
}
static inline void CheckNonEqualsHelper(const char* file,
int line,
const char* expected_source,
void* expected,
const char* value_source,
void* value) {
if (expected == value) {
V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n# Value: %i",
expected_source, value_source, reinterpret_cast<int>(value));
}
}
// Helper function used by the CHECK function when given floating
// point arguments. Should not be called directly.
static inline void CheckEqualsHelper(const char* file,
int line,
const char* expected_source,
double expected,
const char* value_source,
double value) {
// Force values to 64 bit memory to truncate 80 bit precision on IA32.
volatile double* exp = new double[1];
*exp = expected;
volatile double* val = new double[1];
*val = value;
if (*exp != *val) {
V8_Fatal(file, line,
"CHECK_EQ(%s, %s) failed\n# Expected: %f\n# Found: %f",
expected_source, value_source, *exp, *val);
}
delete[] exp;
delete[] val;
}
namespace v8 {
class Value;
template <class T> class Handle;
}
void CheckNonEqualsHelper(const char* file,
int line,
const char* unexpected_source,
v8::Handle<v8::Value> unexpected,
const char* value_source,
v8::Handle<v8::Value> value);
void CheckEqualsHelper(const char* file,
int line,
const char* expected_source,
v8::Handle<v8::Value> expected,
const char* value_source,
v8::Handle<v8::Value> value);
#define CHECK_EQ(expected, value) CheckEqualsHelper(__FILE__, __LINE__, \
#expected, expected, #value, value)
#define CHECK_NE(unexpected, value) CheckNonEqualsHelper(__FILE__, __LINE__, \
#unexpected, unexpected, #value, value)
#define CHECK_GT(a, b) CHECK((a) > (b))
#define CHECK_GE(a, b) CHECK((a) >= (b))
// This is inspired by the static assertion facility in boost. This
// is pretty magical. If it causes you trouble on a platform you may
// find a fix in the boost code.
template <bool> class StaticAssertion;
template <> class StaticAssertion<true> { };
// This macro joins two tokens. If one of the tokens is a macro the
// helper call causes it to be resolved before joining.
#define SEMI_STATIC_JOIN(a, b) SEMI_STATIC_JOIN_HELPER(a, b)
#define SEMI_STATIC_JOIN_HELPER(a, b) a##b
// Causes an error during compilation of the condition is not
// statically known to be true. It is formulated as a typedef so that
// it can be used wherever a typedef can be used. Beware that this
// actually causes each use to introduce a new defined type with a
// name depending on the source line.
template <int> class StaticAssertionHelper { };
#define STATIC_CHECK(test) \
typedef \
StaticAssertionHelper<sizeof(StaticAssertion<static_cast<bool>(test)>)> \
SEMI_STATIC_JOIN(__StaticAssertTypedef__, __LINE__)
// The ASSERT macro is equivalent to CHECK except that it only
// generates code in debug builds. Ditto STATIC_ASSERT.
#ifdef DEBUG
#define ASSERT(condition) CHECK(condition)
#define ASSERT_EQ(v1, v2) CHECK_EQ(v1, v2)
#define ASSERT_NE(v1, v2) CHECK_NE(v1, v2)
#define STATIC_ASSERT(test) STATIC_CHECK(test)
#define SLOW_ASSERT(condition) if (FLAG_enable_slow_asserts) CHECK(condition)
#else
#define ASSERT(condition) ((void) 0)
#define ASSERT_EQ(v1, v2) ((void) 0)
#define ASSERT_NE(v1, v2) ((void) 0)
#define STATIC_ASSERT(test) ((void) 0)
#define SLOW_ASSERT(condition) ((void) 0)
#endif
#define ASSERT_TAG_ALIGNED(address) \
ASSERT((reinterpret_cast<int>(address) & kHeapObjectTagMask) == 0)
#define ASSERT_SIZE_TAG_ALIGNED(size) ASSERT((size & kHeapObjectTagMask) == 0)
#endif // V8_CHECKS_H_

View File

@ -1,140 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#include "v8.h"
#include "bootstrapper.h"
#include "code-stubs.h"
#include "factory.h"
#include "macro-assembler.h"
namespace v8 { namespace internal {
Handle<Code> CodeStub::GetCode() {
uint32_t key = GetKey();
int index = Heap::code_stubs()->FindNumberEntry(key);
if (index == -1) {
HandleScope scope;
// Update the static counter each time a new code stub is generated.
Counters::code_stubs.Increment();
// Generate the new code.
MacroAssembler masm(NULL, 256);
// Nested stubs are not allowed for leafs.
masm.set_allow_stub_calls(AllowsStubCalls());
// Generate the code for the stub.
masm.set_generating_stub(true);
Generate(&masm);
// Create the code object.
CodeDesc desc;
masm.GetCode(&desc);
// Copy the generated code into a heap object, and store the major key.
Code::Flags flags = Code::ComputeFlags(Code::STUB);
Handle<Code> code = Factory::NewCode(desc, NULL, flags);
code->set_major_key(MajorKey());
// Add unresolved entries in the code to the fixup list.
Bootstrapper::AddFixup(*code, &masm);
LOG(CodeCreateEvent("Stub", *code, GetName()));
Counters::total_stubs_code_size.Increment(code->instruction_size());
#ifdef DEBUG
if (FLAG_print_code_stubs) {
Print();
code->Print();
PrintF("\n");
}
#endif
// Update the dictionary and the root in Heap.
Handle<Dictionary> dict =
Factory::DictionaryAtNumberPut(Handle<Dictionary>(Heap::code_stubs()),
key,
code);
Heap::set_code_stubs(*dict);
index = Heap::code_stubs()->FindNumberEntry(key);
}
ASSERT(index != -1);
return Handle<Code>(Code::cast(Heap::code_stubs()->ValueAt(index)));
}
const char* CodeStub::MajorName(CodeStub::Major major_key) {
switch (major_key) {
case CallFunction:
return "CallFunction";
case GenericBinaryOp:
return "GenericBinaryOp";
case SmiOp:
return "SmiOp";
case Compare:
return "Compare";
case RecordWrite:
return "RecordWrite";
case StackCheck:
return "StackCheck";
case UnarySub:
return "UnarySub";
case RevertToNumber:
return "RevertToNumber";
case ToBoolean:
return "ToBoolean";
case Instanceof:
return "Instanceof";
case CounterOp:
return "CounterOp";
case ArgumentsAccess:
return "ArgumentsAccess";
case Runtime:
return "Runtime";
case CEntry:
return "CEntry";
case JSEntry:
return "JSEntry";
case GetProperty:
return "GetProperty";
case SetProperty:
return "SetProperty";
case InvokeBuiltin:
return "InvokeBuiltin";
case JSExit:
return "JSExit";
default:
UNREACHABLE();
return NULL;
}
}
} } // namespace v8::internal

View File

@ -1,109 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#ifndef V8_CODE_STUBS_H_
#define V8_CODE_STUBS_H_
namespace v8 { namespace internal {
// Stub is base classes of all stubs.
class CodeStub BASE_EMBEDDED {
public:
enum Major {
CallFunction,
GenericBinaryOp,
SmiOp,
Compare,
RecordWrite, // Last stub that allows stub calls inside.
StackCheck,
UnarySub,
RevertToNumber,
ToBoolean,
Instanceof,
CounterOp,
ArgumentsAccess,
Runtime,
CEntry,
JSEntry,
GetProperty, // ARM only
SetProperty, // ARM only
InvokeBuiltin, // ARM only
JSExit, // ARM only
NUMBER_OF_IDS
};
// Retrieve the code for the stub. Generate the code if needed.
Handle<Code> GetCode();
static Major MajorKeyFromKey(uint32_t key) {
return static_cast<Major>(MajorKeyBits::decode(key));
};
static int MinorKeyFromKey(uint32_t key) {
return MinorKeyBits::decode(key);
};
static const char* MajorName(Major major_key);
virtual ~CodeStub() {}
protected:
static const int kMajorBits = 5;
static const int kMinorBits = kBitsPerPointer - kMajorBits - kSmiTagSize;
private:
// Generates the assembler code for the stub.
virtual void Generate(MacroAssembler* masm) = 0;
// Returns information for computing the number key.
virtual Major MajorKey() = 0;
virtual int MinorKey() = 0;
// Returns a name for logging/debugging purposes.
virtual const char* GetName() { return MajorName(MajorKey()); }
#ifdef DEBUG
virtual void Print() { PrintF("%s\n", GetName()); }
#endif
// Computes the key based on major and minor.
uint32_t GetKey() {
ASSERT(static_cast<int>(MajorKey()) < NUMBER_OF_IDS);
return MinorKeyBits::encode(MinorKey()) |
MajorKeyBits::encode(MajorKey());
}
bool AllowsStubCalls() { return MajorKey() <= RecordWrite; }
class MajorKeyBits: public BitField<uint32_t, 0, kMajorBits> {};
class MinorKeyBits: public BitField<uint32_t, kMajorBits, kMinorBits> {};
friend class BreakPointIterator;
};
} } // namespace v8::internal
#endif // V8_CODE_STUBS_H_

View File

@ -1,67 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#ifndef V8_CODE_H_
#define V8_CODE_H_
namespace v8 { namespace internal {
// Wrapper class for passing expected and actual parameter counts as
// either registers or immediate values. Used to make sure that the
// caller provides exactly the expected number of parameters to the
// callee.
class ParameterCount BASE_EMBEDDED {
public:
explicit ParameterCount(Register reg)
: reg_(reg), immediate_(0) { }
explicit ParameterCount(int immediate)
: reg_(no_reg), immediate_(immediate) { }
bool is_reg() const { return !reg_.is(no_reg); }
bool is_immediate() const { return !is_reg(); }
Register reg() const {
ASSERT(is_reg());
return reg_;
}
int immediate() const {
ASSERT(is_immediate());
return immediate_;
}
private:
const Register reg_;
const int immediate_;
DISALLOW_IMPLICIT_CONSTRUCTORS(ParameterCount);
};
} } // namespace v8::internal
#endif // V8_CODE_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,376 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#ifndef V8_CODEGEN_ARM_H_
#define V8_CODEGEN_ARM_H_
#include "scopes.h"
namespace v8 { namespace internal {
// Forward declarations
class DeferredCode;
// Mode to overwrite BinaryExpression values.
enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
// -----------------------------------------------------------------------------
// Reference support
// A reference is a C++ stack-allocated object that keeps an ECMA
// reference on the execution stack while in scope. For variables
// the reference is empty, indicating that it isn't necessary to
// store state on the stack for keeping track of references to those.
// For properties, we keep either one (named) or two (indexed) values
// on the execution stack to represent the reference.
enum InitState { CONST_INIT, NOT_CONST_INIT };
enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
class Reference BASE_EMBEDDED {
public:
// The values of the types is important, see size().
enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 };
Reference(CodeGenerator* cgen, Expression* expression);
~Reference();
Expression* expression() const { return expression_; }
Type type() const { return type_; }
void set_type(Type value) {
ASSERT(type_ == ILLEGAL);
type_ = value;
}
// The size of the reference or -1 if the reference is illegal.
int size() const { return type_; }
bool is_illegal() const { return type_ == ILLEGAL; }
bool is_slot() const { return type_ == SLOT; }
bool is_property() const { return type_ == NAMED || type_ == KEYED; }
// Return the name. Only valid for named property references.
Handle<String> GetName();
// Generate code to push the value of the reference on top of the
// expression stack. The reference is expected to be already on top of
// the expression stack, and it is left in place with its value above it.
void GetValue(TypeofState typeof_state);
// Generate code to store the value on top of the expression stack in the
// reference. The reference is expected to be immediately below the value
// on the expression stack. The stored value is left in place (with the
// reference intact below it) to support chained assignments.
void SetValue(InitState init_state);
private:
CodeGenerator* cgen_;
Expression* expression_;
Type type_;
};
// -------------------------------------------------------------------------
// Code generation state
// The state is passed down the AST by the code generator (and back up, in
// the form of the state of the label pair). It is threaded through the
// call stack. Constructing a state implicitly pushes it on the owning code
// generator's stack of states, and destroying one implicitly pops it.
class CodeGenState BASE_EMBEDDED {
public:
// Create an initial code generator state. Destroying the initial state
// leaves the code generator with a NULL state.
explicit CodeGenState(CodeGenerator* owner);
// Create a code generator state based on a code generator's current
// state. The new state has its own typeof state and pair of branch
// labels.
CodeGenState(CodeGenerator* owner,
TypeofState typeof_state,
Label* true_target,
Label* false_target);
// Destroy a code generator state and restore the owning code generator's
// previous state.
~CodeGenState();
TypeofState typeof_state() const { return typeof_state_; }
Label* true_target() const { return true_target_; }
Label* false_target() const { return false_target_; }
private:
CodeGenerator* owner_;
TypeofState typeof_state_;
Label* true_target_;
Label* false_target_;
CodeGenState* previous_;
};
// -----------------------------------------------------------------------------
// CodeGenerator
class CodeGenerator: public Visitor {
public:
// Takes a function literal, generates code for it. This function should only
// be called by compiler.cc.
static Handle<Code> MakeCode(FunctionLiteral* fun,
Handle<Script> script,
bool is_eval);
static void SetFunctionInfo(Handle<JSFunction> fun,
int length,
int function_token_position,
int start_position,
int end_position,
bool is_expression,
bool is_toplevel,
Handle<Script> script);
// Accessors
MacroAssembler* masm() { return masm_; }
CodeGenState* state() { return state_; }
void set_state(CodeGenState* state) { state_ = state; }
void AddDeferred(DeferredCode* code) { deferred_.Add(code); }
private:
// Construction/Destruction
CodeGenerator(int buffer_size, Handle<Script> script, bool is_eval);
virtual ~CodeGenerator() { delete masm_; }
// Accessors
Scope* scope() const { return scope_; }
void ProcessDeferred();
bool is_eval() { return is_eval_; }
// State
bool has_cc() const { return cc_reg_ != al; }
TypeofState typeof_state() const { return state_->typeof_state(); }
Label* true_target() const { return state_->true_target(); }
Label* false_target() const { return state_->false_target(); }
// Node visitors.
#define DEF_VISIT(type) \
void Visit##type(type* node);
NODE_LIST(DEF_VISIT)
#undef DEF_VISIT
// Main code generation function
void GenCode(FunctionLiteral* fun);
// The following are used by class Reference.
void LoadReference(Reference* ref);
void UnloadReference(Reference* ref);
// Support functions for accessing parameters and other operands.
MemOperand ParameterOperand(int index) const {
int num_parameters = scope()->num_parameters();
// index -2 corresponds to the activated closure, -1 corresponds
// to the receiver
ASSERT(-2 <= index && index < num_parameters);
int offset = (1 + num_parameters - index) * kPointerSize;
return MemOperand(fp, offset);
}
MemOperand FunctionOperand() const {
return MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset);
}
MemOperand ContextOperand(Register context, int index) const {
return MemOperand(context, Context::SlotOffset(index));
}
MemOperand SlotOperand(Slot* slot, Register tmp);
// Expressions
MemOperand GlobalObject() const {
return ContextOperand(cp, Context::GLOBAL_INDEX);
}
void LoadCondition(Expression* x,
TypeofState typeof_state,
Label* true_target,
Label* false_target,
bool force_cc);
void Load(Expression* x, TypeofState typeof_state = NOT_INSIDE_TYPEOF);
void LoadGlobal();
void LoadGlobalReceiver(Register scratch);
// Read a value from a slot and leave it on top of the expression stack.
void LoadFromSlot(Slot* slot, TypeofState typeof_state);
// Special code for typeof expressions: Unfortunately, we must
// be careful when loading the expression in 'typeof'
// expressions. We are not allowed to throw reference errors for
// non-existing properties of the global object, so we must make it
// look like an explicit property access, instead of an access
// through the context chain.
void LoadTypeofExpression(Expression* x);
void ToBoolean(Label* true_target, Label* false_target);
void GenericBinaryOperation(Token::Value op);
void Comparison(Condition cc, bool strict = false);
void SmiOperation(Token::Value op, Handle<Object> value, bool reversed);
void CallWithArguments(ZoneList<Expression*>* arguments, int position);
// Control flow
void Branch(bool if_true, Label* L);
void CheckStack();
void CleanStack(int num_bytes);
bool CheckForInlineRuntimeCall(CallRuntime* node);
Handle<JSFunction> BuildBoilerplate(FunctionLiteral* node);
void ProcessDeclarations(ZoneList<Declaration*>* declarations);
Handle<Code> ComputeCallInitialize(int argc);
// Declare global variables and functions in the given array of
// name/value pairs.
void DeclareGlobals(Handle<FixedArray> pairs);
// Instantiate the function boilerplate.
void InstantiateBoilerplate(Handle<JSFunction> boilerplate);
// Support for type checks.
void GenerateIsSmi(ZoneList<Expression*>* args);
void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
void GenerateIsArray(ZoneList<Expression*>* args);
// Support for arguments.length and arguments[?].
void GenerateArgumentsLength(ZoneList<Expression*>* args);
void GenerateArgumentsAccess(ZoneList<Expression*>* args);
// Support for accessing the value field of an object (used by Date).
void GenerateValueOf(ZoneList<Expression*>* args);
void GenerateSetValueOf(ZoneList<Expression*>* args);
// Fast support for charCodeAt(n).
void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
// Fast support for object equality testing.
void GenerateObjectEquals(ZoneList<Expression*>* args);
// Methods and constants for fast case switch statement support.
//
// Only allow fast-case switch if the range of labels is at most
// this factor times the number of case labels.
// Value is derived from comparing the size of code generated by the normal
// switch code for Smi-labels to the size of a single pointer. If code
// quality increases this number should be decreased to match.
static const int kFastSwitchMaxOverheadFactor = 10;
// Minimal number of switch cases required before we allow jump-table
// optimization.
static const int kFastSwitchMinCaseCount = 5;
// The limit of the range of a fast-case switch, as a factor of the number
// of cases of the switch. Each platform should return a value that
// is optimal compared to the default code generated for a switch statement
// on that platform.
int FastCaseSwitchMaxOverheadFactor();
// The minimal number of cases in a switch before the fast-case switch
// optimization is enabled. Each platform should return a value that
// is optimal compared to the default code generated for a switch statement
// on that platform.
int FastCaseSwitchMinCaseCount();
// Allocate a jump table and create code to jump through it.
// Should call GenerateFastCaseSwitchCases to generate the code for
// all the cases at the appropriate point.
void GenerateFastCaseSwitchJumpTable(SwitchStatement* node,
int min_index,
int range,
Label* fail_label,
Vector<Label*> case_targets,
Vector<Label> case_labels);
// Generate the code for cases for the fast case switch.
// Called by GenerateFastCaseSwitchJumpTable.
void GenerateFastCaseSwitchCases(SwitchStatement* node,
Vector<Label> case_labels);
// Fast support for constant-Smi switches.
void GenerateFastCaseSwitchStatement(SwitchStatement* node,
int min_index,
int range,
int default_index);
// Fast support for constant-Smi switches. Tests whether switch statement
// permits optimization and calls GenerateFastCaseSwitch if it does.
// Returns true if the fast-case switch was generated, and false if not.
bool TryGenerateFastCaseSwitchStatement(SwitchStatement* node);
// Bottle-neck interface to call the Assembler to generate the statement
// position. This allows us to easily control whether statement positions
// should be generated or not.
void RecordStatementPosition(Node* node);
// Activation frames.
void EnterJSFrame();
void ExitJSFrame();
bool is_eval_; // Tells whether code is generated for eval.
Handle<Script> script_;
List<DeferredCode*> deferred_;
// Assembler
MacroAssembler* masm_; // to generate code
// Code generation state
Scope* scope_;
Condition cc_reg_;
CodeGenState* state_;
bool is_inside_try_;
int break_stack_height_;
// Labels
Label function_return_;
friend class Reference;
friend class Property;
friend class VariableProxy;
friend class Slot;
DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
};
} } // namespace v8::internal
#endif // V8_CODEGEN_ARM_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,428 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#ifndef V8_CODEGEN_IA32_H_
#define V8_CODEGEN_IA32_H_
#include "scopes.h"
namespace v8 { namespace internal {
// Forward declarations
class DeferredCode;
// Mode to overwrite BinaryExpression values.
enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
enum InitState { CONST_INIT, NOT_CONST_INIT };
enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
// -------------------------------------------------------------------------
// Virtual frame
class VirtualFrame BASE_EMBEDDED {
public:
explicit VirtualFrame(CodeGenerator* cgen);
void Enter();
void Exit();
void AllocateLocals();
Operand Top() const { return Operand(esp, 0); }
Operand Element(int index) const {
return Operand(esp, index * kPointerSize);
}
Operand Local(int index) const {
ASSERT(0 <= index && index < frame_local_count_);
return Operand(ebp, kLocal0Offset - index * kPointerSize);
}
Operand Function() const { return Operand(ebp, kFunctionOffset); }
Operand Context() const { return Operand(ebp, kContextOffset); }
Operand Parameter(int index) const {
ASSERT(-1 <= index && index < parameter_count_);
return Operand(ebp, (1 + parameter_count_ - index) * kPointerSize);
}
Operand Receiver() const { return Parameter(-1); }
inline void Drop(int count);
inline void Pop();
inline void Pop(Register reg);
inline void Pop(Operand operand);
inline void Push(Register reg);
inline void Push(Operand operand);
inline void Push(Immediate immediate);
private:
static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
static const int kFunctionOffset = JavaScriptFrameConstants::kFunctionOffset;
static const int kContextOffset = StandardFrameConstants::kContextOffset;
MacroAssembler* masm_;
int frame_local_count_;
int parameter_count_;
};
// -------------------------------------------------------------------------
// Reference support
// A reference is a C++ stack-allocated object that keeps an ECMA
// reference on the execution stack while in scope. For variables
// the reference is empty, indicating that it isn't necessary to
// store state on the stack for keeping track of references to those.
// For properties, we keep either one (named) or two (indexed) values
// on the execution stack to represent the reference.
class Reference BASE_EMBEDDED {
public:
// The values of the types is important, see size().
enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 };
Reference(CodeGenerator* cgen, Expression* expression);
~Reference();
Expression* expression() const { return expression_; }
Type type() const { return type_; }
void set_type(Type value) {
ASSERT(type_ == ILLEGAL);
type_ = value;
}
// The size of the reference or -1 if the reference is illegal.
int size() const { return type_; }
bool is_illegal() const { return type_ == ILLEGAL; }
bool is_slot() const { return type_ == SLOT; }
bool is_property() const { return type_ == NAMED || type_ == KEYED; }
// Return the name. Only valid for named property references.
Handle<String> GetName();
// Generate code to push the value of the reference on top of the
// expression stack. The reference is expected to be already on top of
// the expression stack, and it is left in place with its value above it.
void GetValue(TypeofState typeof_state);
// Generate code to store the value on top of the expression stack in the
// reference. The reference is expected to be immediately below the value
// on the expression stack. The stored value is left in place (with the
// reference intact below it) to support chained assignments.
void SetValue(InitState init_state);
private:
CodeGenerator* cgen_;
Expression* expression_;
Type type_;
};
// -------------------------------------------------------------------------
// Code generation state
// The state is passed down the AST by the code generator (and back up, in
// the form of the state of the label pair). It is threaded through the
// call stack. Constructing a state implicitly pushes it on the owning code
// generator's stack of states, and destroying one implicitly pops it.
class CodeGenState BASE_EMBEDDED {
public:
// Create an initial code generator state. Destroying the initial state
// leaves the code generator with a NULL state.
explicit CodeGenState(CodeGenerator* owner);
// Create a code generator state based on a code generator's current
// state. The new state has its own access type and pair of branch
// labels, and no reference.
CodeGenState(CodeGenerator* owner,
TypeofState typeof_state,
Label* true_target,
Label* false_target);
// Destroy a code generator state and restore the owning code generator's
// previous state.
~CodeGenState();
TypeofState typeof_state() const { return typeof_state_; }
Label* true_target() const { return true_target_; }
Label* false_target() const { return false_target_; }
private:
CodeGenerator* owner_;
TypeofState typeof_state_;
Label* true_target_;
Label* false_target_;
CodeGenState* previous_;
};
// -------------------------------------------------------------------------
// CodeGenerator
class CodeGenerator: public Visitor {
public:
// Takes a function literal, generates code for it. This function should only
// be called by compiler.cc.
static Handle<Code> MakeCode(FunctionLiteral* fun,
Handle<Script> script,
bool is_eval);
static void SetFunctionInfo(Handle<JSFunction> fun,
int length,
int function_token_position,
int start_position,
int end_position,
bool is_expression,
bool is_toplevel,
Handle<Script> script);
// Accessors
MacroAssembler* masm() { return masm_; }
VirtualFrame* frame() const { return frame_; }
CodeGenState* state() { return state_; }
void set_state(CodeGenState* state) { state_ = state; }
void AddDeferred(DeferredCode* code) { deferred_.Add(code); }
private:
// Construction/Destruction
CodeGenerator(int buffer_size, Handle<Script> script, bool is_eval);
virtual ~CodeGenerator() { delete masm_; }
// Accessors
Scope* scope() const { return scope_; }
void ProcessDeferred();
bool is_eval() { return is_eval_; }
// State
bool has_cc() const { return cc_reg_ >= 0; }
TypeofState typeof_state() const { return state_->typeof_state(); }
Label* true_target() const { return state_->true_target(); }
Label* false_target() const { return state_->false_target(); }
// Node visitors.
#define DEF_VISIT(type) \
void Visit##type(type* node);
NODE_LIST(DEF_VISIT)
#undef DEF_VISIT
// Main code generation function
void GenCode(FunctionLiteral* fun);
// The following are used by class Reference.
void LoadReference(Reference* ref);
void UnloadReference(Reference* ref);
Operand ContextOperand(Register context, int index) const {
return Operand(context, Context::SlotOffset(index));
}
Operand SlotOperand(Slot* slot, Register tmp);
// Expressions
Operand GlobalObject() const {
return ContextOperand(esi, Context::GLOBAL_INDEX);
}
void LoadCondition(Expression* x,
TypeofState typeof_state,
Label* true_target,
Label* false_target,
bool force_cc);
void Load(Expression* x, TypeofState typeof_state = NOT_INSIDE_TYPEOF);
void LoadGlobal();
void LoadGlobalReceiver(Register scratch);
// Read a value from a slot and leave it on top of the expression stack.
void LoadFromSlot(Slot* slot, TypeofState typeof_state);
// Special code for typeof expressions: Unfortunately, we must
// be careful when loading the expression in 'typeof'
// expressions. We are not allowed to throw reference errors for
// non-existing properties of the global object, so we must make it
// look like an explicit property access, instead of an access
// through the context chain.
void LoadTypeofExpression(Expression* x);
void ToBoolean(Label* true_target, Label* false_target);
void GenericBinaryOperation(Token::Value op,
const OverwriteMode overwrite_mode = NO_OVERWRITE);
void Comparison(Condition cc, bool strict = false);
// Inline small integer literals. To prevent long attacker-controlled byte
// sequences, we only inline small Smis.
static const int kMaxSmiInlinedBits = 16;
bool IsInlineSmi(Literal* literal);
void SmiComparison(Condition cc, Handle<Object> value, bool strict = false);
void SmiOperation(Token::Value op,
Handle<Object> value,
bool reversed,
OverwriteMode overwrite_mode);
void CallWithArguments(ZoneList<Expression*>* arguments, int position);
// Control flow
void Branch(bool if_true, Label* L);
void CheckStack();
void CleanStack(int num_bytes);
bool CheckForInlineRuntimeCall(CallRuntime* node);
Handle<JSFunction> BuildBoilerplate(FunctionLiteral* node);
void ProcessDeclarations(ZoneList<Declaration*>* declarations);
Handle<Code> ComputeCallInitialize(int argc);
// Declare global variables and functions in the given array of
// name/value pairs.
void DeclareGlobals(Handle<FixedArray> pairs);
// Instantiate the function boilerplate.
void InstantiateBoilerplate(Handle<JSFunction> boilerplate);
// Support for type checks.
void GenerateIsSmi(ZoneList<Expression*>* args);
void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
void GenerateIsArray(ZoneList<Expression*>* args);
// Support for arguments.length and arguments[?].
void GenerateArgumentsLength(ZoneList<Expression*>* args);
void GenerateArgumentsAccess(ZoneList<Expression*>* args);
// Support for accessing the value field of an object (used by Date).
void GenerateValueOf(ZoneList<Expression*>* args);
void GenerateSetValueOf(ZoneList<Expression*>* args);
// Fast support for charCodeAt(n).
void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
// Fast support for object equality testing.
void GenerateObjectEquals(ZoneList<Expression*>* args);
// Methods and constants for fast case switch statement support.
//
// Only allow fast-case switch if the range of labels is at most
// this factor times the number of case labels.
// Value is derived from comparing the size of code generated by the normal
// switch code for Smi-labels to the size of a single pointer. If code
// quality increases this number should be decreased to match.
static const int kFastSwitchMaxOverheadFactor = 5;
// Minimal number of switch cases required before we allow jump-table
// optimization.
static const int kFastSwitchMinCaseCount = 5;
// The limit of the range of a fast-case switch, as a factor of the number
// of cases of the switch. Each platform should return a value that
// is optimal compared to the default code generated for a switch statement
// on that platform.
int FastCaseSwitchMaxOverheadFactor();
// The minimal number of cases in a switch before the fast-case switch
// optimization is enabled. Each platform should return a value that
// is optimal compared to the default code generated for a switch statement
// on that platform.
int FastCaseSwitchMinCaseCount();
// Allocate a jump table and create code to jump through it.
// Should call GenerateFastCaseSwitchCases to generate the code for
// all the cases at the appropriate point.
void GenerateFastCaseSwitchJumpTable(SwitchStatement* node,
int min_index,
int range,
Label* fail_label,
Vector<Label*> case_targets,
Vector<Label> case_labels);
// Generate the code for cases for the fast case switch.
// Called by GenerateFastCaseSwitchJumpTable.
void GenerateFastCaseSwitchCases(SwitchStatement* node,
Vector<Label> case_labels);
// Fast support for constant-Smi switches.
void GenerateFastCaseSwitchStatement(SwitchStatement* node,
int min_index,
int range,
int default_index);
// Fast support for constant-Smi switches. Tests whether switch statement
// permits optimization and calls GenerateFastCaseSwitch if it does.
// Returns true if the fast-case switch was generated, and false if not.
bool TryGenerateFastCaseSwitchStatement(SwitchStatement* node);
// Bottle-neck interface to call the Assembler to generate the statement
// position. This allows us to easily control whether statement positions
// should be generated or not.
void RecordStatementPosition(Node* node);
bool is_eval_; // Tells whether code is generated for eval.
Handle<Script> script_;
List<DeferredCode*> deferred_;
// Assembler
MacroAssembler* masm_; // to generate code
// Code generation state
Scope* scope_;
VirtualFrame* frame_;
Condition cc_reg_;
CodeGenState* state_;
bool is_inside_try_;
int break_stack_height_;
// Labels
Label function_return_;
friend class VirtualFrame;
friend class Reference;
DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
};
} } // namespace v8::internal
#endif // V8_CODEGEN_IA32_H_

View File

@ -1,76 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#ifndef V8_CODEGEN_INL_H_
#define V8_CODEGEN_INL_H_
#include "codegen.h"
namespace v8 { namespace internal {
// -----------------------------------------------------------------------------
// Support for "structured" code comments.
//
// By selecting matching brackets in disassembler output,
// code segments can be identified more easily.
#ifdef DEBUG
class Comment BASE_EMBEDDED {
public:
Comment(MacroAssembler* masm, const char* msg)
: masm_(masm),
msg_(msg) {
masm_->RecordComment(msg);
}
~Comment() {
if (msg_[0] == '[')
masm_->RecordComment("]");
}
private:
MacroAssembler* masm_;
const char* msg_;
};
#else
class Comment BASE_EMBEDDED {
public:
Comment(MacroAssembler*, const char*) {}
};
#endif // DEBUG
} } // namespace v8::internal
#endif // V8_CODEGEN_INL_H_

View File

@ -1,474 +0,0 @@
// Copyright 2007-2008 the V8 project 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.
#include "v8.h"
#include "bootstrapper.h"
#include "codegen-inl.h"
#include "debug.h"
#include "prettyprinter.h"
#include "scopeinfo.h"
#include "runtime.h"
#include "stub-cache.h"
namespace v8 { namespace internal {
DeferredCode::DeferredCode(CodeGenerator* generator)
: masm_(generator->masm()),
generator_(generator),
statement_position_(masm_->last_statement_position()),
position_(masm_->last_position()) {
generator->AddDeferred(this);
#ifdef DEBUG
comment_ = "";
#endif
}
void CodeGenerator::ProcessDeferred() {
while (!deferred_.is_empty()) {
DeferredCode* code = deferred_.RemoveLast();
MacroAssembler* masm = code->masm();
// Record position of deferred code stub.
if (code->statement_position() != RelocInfo::kNoPosition) {
masm->RecordStatementPosition(code->statement_position());
}
if (code->position() != RelocInfo::kNoPosition) {
masm->RecordPosition(code->position());
}
// Bind labels and generate the code.
masm->bind(code->enter());
Comment cmnt(masm, code->comment());
code->Generate();
if (code->exit()->is_bound()) {
masm->jmp(code->exit()); // platform independent?
}
}
}
// Generate the code. Takes a function literal, generates code for it, assemble
// all the pieces into a Code object. This function is only to be called by
// the compiler.cc code.
Handle<Code> CodeGenerator::MakeCode(FunctionLiteral* flit,
Handle<Script> script,
bool is_eval) {
#ifdef ENABLE_DISASSEMBLER
bool print_code = FLAG_print_code && !Bootstrapper::IsActive();
#endif
#ifdef DEBUG
bool print_source = false;
bool print_ast = false;
const char* ftype;
if (Bootstrapper::IsActive()) {
print_source = FLAG_print_builtin_source;
print_ast = FLAG_print_builtin_ast;
print_code = FLAG_print_builtin_code;
ftype = "builtin";
} else {
print_source = FLAG_print_source;
print_ast = FLAG_print_ast;
ftype = "user-defined";
}
if (FLAG_trace_codegen || print_source || print_ast) {
PrintF("*** Generate code for %s function: ", ftype);
flit->name()->ShortPrint();
PrintF(" ***\n");
}
if (print_source) {
PrintF("--- Source from AST ---\n%s\n", PrettyPrinter().PrintProgram(flit));
}
if (print_ast) {
PrintF("--- AST ---\n%s\n", AstPrinter().PrintProgram(flit));
}
#endif // DEBUG
// Generate code.
const int initial_buffer_size = 4 * KB;
CodeGenerator cgen(initial_buffer_size, script, is_eval);
cgen.GenCode(flit);
if (cgen.HasStackOverflow()) {
ASSERT(!Top::has_pending_exception());
return Handle<Code>::null();
}
// Process any deferred code.
cgen.ProcessDeferred();
// Allocate and install the code.
CodeDesc desc;
cgen.masm()->GetCode(&desc);
ScopeInfo<> sinfo(flit->scope());
Code::Flags flags = Code::ComputeFlags(Code::FUNCTION);
Handle<Code> code = Factory::NewCode(desc, &sinfo, flags);
// Add unresolved entries in the code to the fixup list.
Bootstrapper::AddFixup(*code, cgen.masm());
#ifdef ENABLE_DISASSEMBLER
if (print_code) {
// Print the source code if available.
if (!script->IsUndefined() && !script->source()->IsUndefined()) {
PrintF("--- Raw source ---\n");
StringInputBuffer stream(String::cast(script->source()));
stream.Seek(flit->start_position());
// flit->end_position() points to the last character in the stream. We
// need to compensate by adding one to calculate the length.
int source_len = flit->end_position() - flit->start_position() + 1;
for (int i = 0; i < source_len; i++) {
if (stream.has_more()) PrintF("%c", stream.GetNext());
}
PrintF("\n\n");
}
PrintF("--- Code ---\n");
code->Disassemble();
}
#endif // ENABLE_DISASSEMBLER
if (!code.is_null()) {
Counters::total_compiled_code_size.Increment(code->instruction_size());
}
return code;
}
// Sets the function info on a function.
// The start_position points to the first '(' character after the function name
// in the full script source. When counting characters in the script source the
// the first character is number 0 (not 1).
void CodeGenerator::SetFunctionInfo(Handle<JSFunction> fun,
int length,
int function_token_position,
int start_position,
int end_position,
bool is_expression,
bool is_toplevel,
Handle<Script> script) {
fun->shared()->set_length(length);
fun->shared()->set_formal_parameter_count(length);
fun->shared()->set_script(*script);
fun->shared()->set_function_token_position(function_token_position);
fun->shared()->set_start_position(start_position);
fun->shared()->set_end_position(end_position);
fun->shared()->set_is_expression(is_expression);
fun->shared()->set_is_toplevel(is_toplevel);
}
static Handle<Code> ComputeLazyCompile(int argc) {
CALL_HEAP_FUNCTION(StubCache::ComputeLazyCompile(argc), Code);
}
Handle<JSFunction> CodeGenerator::BuildBoilerplate(FunctionLiteral* node) {
// Determine if the function can be lazily compiled. This is
// necessary to allow some of our builtin JS files to be lazily
// compiled. These builtins cannot be handled lazily by the parser,
// since we have to know if a function uses the special natives
// syntax, which is something the parser records.
bool allow_lazy = node->AllowsLazyCompilation();
// Generate code
Handle<Code> code;
if (FLAG_lazy && allow_lazy) {
code = ComputeLazyCompile(node->num_parameters());
} else {
code = MakeCode(node, script_, false);
// Check for stack-overflow exception.
if (code.is_null()) {
SetStackOverflow();
return Handle<JSFunction>::null();
}
// Function compilation complete.
LOG(CodeCreateEvent("Function", *code, *node->name()));
}
// Create a boilerplate function.
Handle<JSFunction> function =
Factory::NewFunctionBoilerplate(node->name(),
node->materialized_literal_count(),
node->contains_array_literal(),
code);
CodeGenerator::SetFunctionInfo(function, node->num_parameters(),
node->function_token_position(),
node->start_position(), node->end_position(),
node->is_expression(), false, script_);
// Notify debugger that a new function has been added.
Debugger::OnNewFunction(function);
// Set the expected number of properties for instances and return
// the resulting function.
SetExpectedNofPropertiesFromEstimate(function,
node->expected_property_count());
return function;
}
Handle<Code> CodeGenerator::ComputeCallInitialize(int argc) {
CALL_HEAP_FUNCTION(StubCache::ComputeCallInitialize(argc), Code);
}
void CodeGenerator::ProcessDeclarations(ZoneList<Declaration*>* declarations) {
int length = declarations->length();
int globals = 0;
for (int i = 0; i < length; i++) {
Declaration* node = declarations->at(i);
Variable* var = node->proxy()->var();
Slot* slot = var->slot();
// If it was not possible to allocate the variable at compile
// time, we need to "declare" it at runtime to make sure it
// actually exists in the local context.
if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
VisitDeclaration(node);
} else {
// Count global variables and functions for later processing
globals++;
}
}
// Return in case of no declared global functions or variables.
if (globals == 0) return;
// Compute array of global variable and function declarations.
Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED);
for (int j = 0, i = 0; i < length; i++) {
Declaration* node = declarations->at(i);
Variable* var = node->proxy()->var();
Slot* slot = var->slot();
if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
// Skip - already processed.
} else {
array->set(j++, *(var->name()));
if (node->fun() == NULL) {
if (var->mode() == Variable::CONST) {
// In case this is const property use the hole.
array->set_the_hole(j++);
} else {
array->set_undefined(j++);
}
} else {
Handle<JSFunction> function = BuildBoilerplate(node->fun());
// Check for stack-overflow exception.
if (HasStackOverflow()) return;
array->set(j++, *function);
}
}
}
// Invoke the platform-dependent code generator to do the actual
// declaration the global variables and functions.
DeclareGlobals(array);
}
struct InlineRuntimeLUT {
void (CodeGenerator::*method)(ZoneList<Expression*>*);
const char* name;
};
bool CodeGenerator::CheckForInlineRuntimeCall(CallRuntime* node) {
ZoneList<Expression*>* args = node->arguments();
// Special cases: These 'runtime calls' manipulate the current
// frame and are only used 1 or two places, so we generate them
// inline instead of generating calls to them. They are used
// for implementing Function.prototype.call() and
// Function.prototype.apply().
static const InlineRuntimeLUT kInlineRuntimeLUT[] = {
{&v8::internal::CodeGenerator::GenerateIsSmi,
"_IsSmi"},
{&v8::internal::CodeGenerator::GenerateIsNonNegativeSmi,
"_IsNonNegativeSmi"},
{&v8::internal::CodeGenerator::GenerateIsArray,
"_IsArray"},
{&v8::internal::CodeGenerator::GenerateArgumentsLength,
"_ArgumentsLength"},
{&v8::internal::CodeGenerator::GenerateArgumentsAccess,
"_Arguments"},
{&v8::internal::CodeGenerator::GenerateValueOf,
"_ValueOf"},
{&v8::internal::CodeGenerator::GenerateSetValueOf,
"_SetValueOf"},
{&v8::internal::CodeGenerator::GenerateFastCharCodeAt,
"_FastCharCodeAt"},
{&v8::internal::CodeGenerator::GenerateObjectEquals,
"_ObjectEquals"}
};
if (node->name()->length() > 0 && node->name()->Get(0) == '_') {
for (unsigned i = 0;
i < sizeof(kInlineRuntimeLUT) / sizeof(InlineRuntimeLUT);
i++) {
const InlineRuntimeLUT* entry = kInlineRuntimeLUT + i;
if (node->name()->IsEqualTo(CStrVector(entry->name))) {
((*this).*(entry->method))(args);
return true;
}
}
}
return false;
}
void CodeGenerator::GenerateFastCaseSwitchStatement(SwitchStatement* node,
int min_index,
int range,
int default_index) {
ZoneList<CaseClause*>* cases = node->cases();
int length = cases->length();
// Label pointer per number in range
SmartPointer<Label*> case_targets(NewArray<Label*>(range));
// Label per switch case
SmartPointer<Label> case_labels(NewArray<Label>(length));
Label* fail_label = default_index >= 0 ? &(case_labels[default_index])
: node->break_target();
// Populate array of label pointers for each number in the range.
// Initally put the failure label everywhere.
for (int i = 0; i < range; i++) {
case_targets[i] = fail_label;
}
// Overwrite with label of a case for the number value of that case.
// (In reverse order, so that if the same label occurs twice, the
// first one wins).
for (int i = length-1; i >= 0 ; i--) {
CaseClause* clause = cases->at(i);
if (!clause->is_default()) {
Object* label_value = *(clause->label()->AsLiteral()->handle());
int case_value = Smi::cast(label_value)->value();
case_targets[case_value - min_index] = &(case_labels[i]);
}
}
GenerateFastCaseSwitchJumpTable(node,
min_index,
range,
fail_label,
Vector<Label*>(*case_targets, range),
Vector<Label>(*case_labels, length));
}
void CodeGenerator::GenerateFastCaseSwitchCases(
SwitchStatement* node,
Vector<Label> case_labels) {
ZoneList<CaseClause*>* cases = node->cases();
int length = cases->length();
for (int i = 0; i < length; i++) {
Comment cmnt(masm(), "[ Case clause");
masm()->bind(&(case_labels[i]));
VisitStatements(cases->at(i)->statements());
}
masm()->bind(node->break_target());
}
bool CodeGenerator::TryGenerateFastCaseSwitchStatement(SwitchStatement* node) {
ZoneList<CaseClause*>* cases = node->cases();
int length = cases->length();
if (length < FastCaseSwitchMinCaseCount()) {
return false;
}
// Test whether fast-case should be used.
int default_index = -1;
int min_index = Smi::kMaxValue;
int max_index = Smi::kMinValue;
for (int i = 0; i < length; i++) {
CaseClause* clause = cases->at(i);
if (clause->is_default()) {
if (default_index >= 0) {
return false; // More than one default label:
// Defer to normal case for error.
}
default_index = i;
} else {
Expression* label = clause->label();
Literal* literal = label->AsLiteral();
if (literal == NULL) {
return false; // fail fast case
}
Object* value = *(literal->handle());
if (!value->IsSmi()) {
return false;
}
int smi = Smi::cast(value)->value();
if (smi < min_index) { min_index = smi; }
if (smi > max_index) { max_index = smi; }
}
}
// All labels are known to be Smis.
int range = max_index - min_index + 1; // |min..max| inclusive
if (range / FastCaseSwitchMaxOverheadFactor() > length) {
return false; // range of labels is too sparse
}
// Optimization accepted, generate code.
GenerateFastCaseSwitchStatement(node, min_index, range, default_index);
return true;
}
const char* RuntimeStub::GetName() {
return Runtime::FunctionForId(id_)->stub_name;
}
void RuntimeStub::Generate(MacroAssembler* masm) {
masm->TailCallRuntime(ExternalReference(id_), num_arguments_);
}
void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
switch (type_) {
case READ_LENGTH: GenerateReadLength(masm); break;
case READ_ELEMENT: GenerateReadElement(masm); break;
case NEW_OBJECT: GenerateNewObject(masm); break;
}
}
} } // namespace v8::internal

View File

@ -1,288 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#ifndef V8_CODEGEN_H_
#define V8_CODEGEN_H_
#include "ast.h"
#include "code-stubs.h"
#include "runtime.h"
// Include the declaration of the architecture defined class CodeGenerator.
// The contract to the shared code is that the the CodeGenerator is a subclass
// of Visitor and that the following methods are available publicly:
// CodeGenerator::MakeCode
// CodeGenerator::SetFunctionInfo
// CodeGenerator::AddDeferred
// CodeGenerator::masm
//
// These methods are either used privately by the shared code or implemented as
// shared code:
// CodeGenerator::CodeGenerator
// CodeGenerator::~CodeGenerator
// CodeGenerator::ProcessDeferred
// CodeGenerator::GenCode
// CodeGenerator::BuildBoilerplate
// CodeGenerator::ComputeCallInitialize
// CodeGenerator::ProcessDeclarations
// CodeGenerator::DeclareGlobals
// CodeGenerator::CheckForInlineRuntimeCall
// CodeGenerator::GenerateFastCaseSwitchStatement
// CodeGenerator::GenerateFastCaseSwitchCases
// CodeGenerator::TryGenerateFastCaseSwitchStatement
// CodeGenerator::GenerateFastCaseSwitchJumpTable
// CodeGenerator::FastCaseSwitchMinCaseCount
// CodeGenerator::FastCaseSwitchMaxOverheadFactor
#if defined(ARM)
#include "codegen-arm.h"
#else
#include "codegen-ia32.h"
#endif
namespace v8 { namespace internal {
// Use lazy compilation; defaults to true.
// NOTE: Do not remove non-lazy compilation until we can properly
// install extensions with lazy compilation enabled. At the
// moment, this doesn't work for the extensions in Google3,
// and we can only run the tests with --nolazy.
// Deferred code objects are small pieces of code that are compiled
// out of line. They are used to defer the compilation of uncommon
// paths thereby avoiding expensive jumps around uncommon code parts.
class DeferredCode: public ZoneObject {
public:
explicit DeferredCode(CodeGenerator* generator);
virtual ~DeferredCode() { }
virtual void Generate() = 0;
MacroAssembler* masm() const { return masm_; }
CodeGenerator* generator() const { return generator_; }
Label* enter() { return &enter_; }
Label* exit() { return &exit_; }
int statement_position() const { return statement_position_; }
int position() const { return position_; }
#ifdef DEBUG
void set_comment(const char* comment) { comment_ = comment; }
const char* comment() const { return comment_; }
#else
inline void set_comment(const char* comment) { }
const char* comment() const { return ""; }
#endif
protected:
// The masm_ field is manipulated when compiling stubs with the
// BEGIN_STUB and END_STUB macros. For that reason, it cannot be
// constant.
MacroAssembler* masm_;
private:
CodeGenerator* const generator_;
Label enter_;
Label exit_;
int statement_position_;
int position_;
#ifdef DEBUG
const char* comment_;
#endif
DISALLOW_COPY_AND_ASSIGN(DeferredCode);
};
// RuntimeStub models code stubs calling entry points in the Runtime class.
class RuntimeStub : public CodeStub {
public:
explicit RuntimeStub(Runtime::FunctionId id, int num_arguments)
: id_(id), num_arguments_(num_arguments) { }
void Generate(MacroAssembler* masm);
// Disassembler support. It is useful to be able to print the name
// of the runtime function called through this stub.
static const char* GetNameFromMinorKey(int minor_key) {
return Runtime::FunctionForId(IdField::decode(minor_key))->stub_name;
}
private:
Runtime::FunctionId id_;
int num_arguments_;
class ArgumentField: public BitField<int, 0, 16> {};
class IdField: public BitField<Runtime::FunctionId, 16, kMinorBits - 16> {};
Major MajorKey() { return Runtime; }
int MinorKey() {
return IdField::encode(id_) | ArgumentField::encode(num_arguments_);
}
const char* GetName();
#ifdef DEBUG
void Print() {
PrintF("RuntimeStub (id %s)\n", Runtime::FunctionForId(id_)->name);
}
#endif
};
class StackCheckStub : public CodeStub {
public:
StackCheckStub() { }
void Generate(MacroAssembler* masm);
private:
const char* GetName() { return "StackCheckStub"; }
Major MajorKey() { return StackCheck; }
int MinorKey() { return 0; }
};
class UnarySubStub : public CodeStub {
public:
UnarySubStub() { }
private:
Major MajorKey() { return UnarySub; }
int MinorKey() { return 0; }
void Generate(MacroAssembler* masm);
const char* GetName() { return "UnarySubStub"; }
};
class CEntryStub : public CodeStub {
public:
CEntryStub() { }
void Generate(MacroAssembler* masm) { GenerateBody(masm, false); }
protected:
void GenerateBody(MacroAssembler* masm, bool is_debug_break);
void GenerateCore(MacroAssembler* masm,
Label* throw_normal_exception,
Label* throw_out_of_memory_exception,
StackFrame::Type frame_type,
bool do_gc);
void GenerateThrowTOS(MacroAssembler* masm);
void GenerateThrowOutOfMemory(MacroAssembler* masm);
private:
Major MajorKey() { return CEntry; }
int MinorKey() { return 0; }
const char* GetName() { return "CEntryStub"; }
};
class CEntryDebugBreakStub : public CEntryStub {
public:
CEntryDebugBreakStub() { }
void Generate(MacroAssembler* masm) { GenerateBody(masm, true); }
private:
int MinorKey() { return 1; }
const char* GetName() { return "CEntryDebugBreakStub"; }
};
class JSEntryStub : public CodeStub {
public:
JSEntryStub() { }
void Generate(MacroAssembler* masm) { GenerateBody(masm, false); }
protected:
void GenerateBody(MacroAssembler* masm, bool is_construct);
private:
Major MajorKey() { return JSEntry; }
int MinorKey() { return 0; }
const char* GetName() { return "JSEntryStub"; }
};
class JSConstructEntryStub : public JSEntryStub {
public:
JSConstructEntryStub() { }
void Generate(MacroAssembler* masm) { GenerateBody(masm, true); }
private:
int MinorKey() { return 1; }
const char* GetName() { return "JSConstructEntryStub"; }
};
class ArgumentsAccessStub: public CodeStub {
public:
enum Type {
READ_LENGTH,
READ_ELEMENT,
NEW_OBJECT
};
explicit ArgumentsAccessStub(Type type) : type_(type) { }
private:
Type type_;
Major MajorKey() { return ArgumentsAccess; }
int MinorKey() { return type_; }
void Generate(MacroAssembler* masm);
void GenerateReadLength(MacroAssembler* masm);
void GenerateReadElement(MacroAssembler* masm);
void GenerateNewObject(MacroAssembler* masm);
const char* GetName() { return "ArgumentsAccessStub"; }
#ifdef DEBUG
void Print() {
PrintF("ArgumentsAccessStub (type %d)\n", type_);
}
#endif
};
} // namespace internal
} // namespace v8
#endif // V8_CODEGEN_H_

View File

@ -1,180 +0,0 @@
// Copyright 2008 the V8 project 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.
#include "v8.h"
#include "compilation-cache.h"
namespace v8 { namespace internal {
enum {
NUMBER_OF_ENTRY_KINDS = CompilationCache::LAST_ENTRY + 1
};
// Keep separate tables for the different entry kinds.
static Object* tables[NUMBER_OF_ENTRY_KINDS] = { 0, };
static Handle<CompilationCacheTable> AllocateTable(int size) {
CALL_HEAP_FUNCTION(CompilationCacheTable::Allocate(size),
CompilationCacheTable);
}
static Handle<CompilationCacheTable> GetTable(CompilationCache::Entry entry) {
Handle<CompilationCacheTable> result;
if (tables[entry]->IsUndefined()) {
static const int kInitialCacheSize = 64;
result = AllocateTable(kInitialCacheSize);
tables[entry] = *result;
} else {
CompilationCacheTable* table = CompilationCacheTable::cast(tables[entry]);
result = Handle<CompilationCacheTable>(table);
}
return result;
}
// We only re-use a cached function for some script source code if the
// script originates from the same places. This is to avoid issues
// when reporting errors, etc.
static bool HasOrigin(Handle<JSFunction> boilerplate,
Handle<Object> name,
int line_offset,
int column_offset) {
Handle<Script> script =
Handle<Script>(Script::cast(boilerplate->shared()->script()));
// If the script name isn't set, the boilerplate script should have
// an undefined name to have the same origin.
if (name.is_null()) {
return script->name()->IsUndefined();
}
// Do the fast bailout checks first.
if (line_offset != script->line_offset()->value()) return false;
if (column_offset != script->column_offset()->value()) return false;
// Check that both names are strings. If not, no match.
if (!name->IsString() || !script->name()->IsString()) return false;
// Compare the two name strings for equality.
return String::cast(*name)->Equals(String::cast(script->name()));
}
static Handle<JSFunction> Lookup(Handle<String> source,
CompilationCache::Entry entry) {
// Make sure not to leak the table into the surrounding handle
// scope. Otherwise, we risk keeping old tables around even after
// having cleared the cache.
Object* result;
{ HandleScope scope;
Handle<CompilationCacheTable> table = GetTable(entry);
result = table->Lookup(*source);
}
if (result->IsJSFunction()) {
return Handle<JSFunction>(JSFunction::cast(result));
} else {
return Handle<JSFunction>::null();
}
}
Handle<JSFunction> CompilationCache::LookupScript(Handle<String> source,
Handle<Object> name,
int line_offset,
int column_offset) {
Handle<JSFunction> result = Lookup(source, SCRIPT);
if (result.is_null()) {
Counters::compilation_cache_misses.Increment();
} else if (HasOrigin(result, name, line_offset, column_offset)) {
Counters::compilation_cache_hits.Increment();
} else {
result = Handle<JSFunction>::null();
Counters::compilation_cache_misses.Increment();
}
return result;
}
Handle<JSFunction> CompilationCache::LookupEval(Handle<String> source,
Entry entry) {
ASSERT(entry == EVAL_GLOBAL || entry == EVAL_CONTEXTUAL);
Handle<JSFunction> result = Lookup(source, entry);
if (result.is_null()) {
Counters::compilation_cache_misses.Increment();
} else {
Counters::compilation_cache_hits.Increment();
}
return result;
}
void CompilationCache::PutFunction(Handle<String> source,
Entry entry,
Handle<JSFunction> boilerplate) {
HandleScope scope;
ASSERT(boilerplate->IsBoilerplate());
Handle<CompilationCacheTable> table = GetTable(entry);
CALL_HEAP_FUNCTION_VOID(table->Put(*source, *boilerplate));
}
Handle<FixedArray> CompilationCache::LookupRegExp(Handle<String> source,
JSRegExp::Flags flags) {
Handle<CompilationCacheTable> table = GetTable(REGEXP);
Object* result = table->LookupRegExp(*source, flags);
if (result->IsFixedArray()) {
Counters::regexp_cache_hits.Increment();
return Handle<FixedArray>(FixedArray::cast(result));
} else {
Counters::regexp_cache_misses.Increment();
return Handle<FixedArray>();
}
}
void CompilationCache::PutRegExp(Handle<String> source,
JSRegExp::Flags flags,
Handle<FixedArray> data) {
HandleScope scope;
Handle<CompilationCacheTable> table = GetTable(REGEXP);
CALL_HEAP_FUNCTION_VOID(table->PutRegExp(*source, flags, *data));
}
void CompilationCache::Clear() {
for (int i = 0; i < NUMBER_OF_ENTRY_KINDS; i++) {
tables[i] = Heap::undefined_value();
}
}
void CompilationCache::Iterate(ObjectVisitor* v) {
v->VisitPointers(&tables[0], &tables[NUMBER_OF_ENTRY_KINDS]);
}
} } // namespace v8::internal

View File

@ -1,98 +0,0 @@
// Copyright 2008 the V8 project 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.
#ifndef V8_COMPILATION_CACHE_H_
#define V8_COMPILATION_CACHE_H_
namespace v8 { namespace internal {
// The compilation cache keeps function boilerplates for compiled
// scripts and evals. The boilerplates are looked up using the source
// string as the key.
class CompilationCache {
public:
// The same source code string has different compiled code for
// scripts and evals. Internally, we use separate caches to avoid
// getting the wrong kind of entry when looking up.
enum Entry {
SCRIPT,
EVAL_GLOBAL,
EVAL_CONTEXTUAL,
REGEXP,
LAST_ENTRY = REGEXP
};
// Finds the script function boilerplate for a source
// string. Returns an empty handle if the cache doesn't contain a
// script for the given source string with the right origin.
static Handle<JSFunction> LookupScript(Handle<String> source,
Handle<Object> name,
int line_offset,
int column_offset);
// Finds the function boilerplate for a source string for
// eval. Returns an empty handle if the cache doesn't contain a
// script for the given source string.
static Handle<JSFunction> LookupEval(Handle<String> source,
Entry entry);
// Returns the regexp data associated with the given regexp if it
// is in cache, otherwise an empty handle.
static Handle<FixedArray> LookupRegExp(Handle<String> source,
JSRegExp::Flags flags);
// Associate the (source, flags) pair to the given regexp data.
// This may overwrite an existing mapping.
static void PutRegExp(Handle<String> source,
JSRegExp::Flags flags,
Handle<FixedArray> data);
// Associate the (source, kind) pair to the boilerplate. This may
// overwrite an existing mapping.
static void PutFunction(Handle<String> source,
Entry entry,
Handle<JSFunction> boilerplate);
// Clear the cache - also used to initialize the cache at startup.
static void Clear();
// GC support.
static void Iterate(ObjectVisitor* v);
// Notify the cache that a mark-sweep garbage collection is about to
// take place. This is used to retire entries from the cache to
// avoid keeping them alive too long without using them. For now, we
// just clear the cache but we should consider are more
// sophisticated LRU scheme.
static void MarkCompactPrologue() { Clear(); }
};
} } // namespace v8::internal
#endif // V8_COMPILATION_CACHE_H_

View File

@ -1,294 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#include "v8.h"
#include "bootstrapper.h"
#include "codegen-inl.h"
#include "compilation-cache.h"
#include "compiler.h"
#include "debug.h"
#include "scopes.h"
#include "rewriter.h"
#include "usage-analyzer.h"
namespace v8 { namespace internal {
static Handle<Code> MakeCode(FunctionLiteral* literal,
Handle<Script> script,
bool is_eval) {
ASSERT(literal != NULL);
// Rewrite the AST by introducing .result assignments where needed.
if (!Rewriter::Process(literal) || !AnalyzeVariableUsage(literal)) {
// Signal a stack overflow by returning a null handle. The stack
// overflow exception will be thrown by the caller.
return Handle<Code>::null();
}
// Compute top scope and allocate variables. For lazy compilation
// the top scope only contains the single lazily compiled function,
// so this doesn't re-allocate variables repeatedly.
Scope* top = literal->scope();
while (top->outer_scope() != NULL) top = top->outer_scope();
top->AllocateVariables();
#ifdef DEBUG
if (Bootstrapper::IsActive() ?
FLAG_print_builtin_scopes :
FLAG_print_scopes) {
literal->scope()->Print();
}
#endif
// Generate code and return it.
Handle<Code> result = CodeGenerator::MakeCode(literal, script, is_eval);
return result;
}
static Handle<JSFunction> MakeFunction(bool is_global,
bool is_eval,
Handle<Script> script,
v8::Extension* extension,
ScriptDataImpl* pre_data) {
ZoneScope zone_scope(DELETE_ON_EXIT);
// Make sure we have an initial stack limit.
StackGuard guard;
PostponeInterruptsScope postpone;
// Notify debugger
Debugger::OnBeforeCompile(script);
// Only allow non-global compiles for eval.
ASSERT(is_eval || is_global);
// Build AST.
FunctionLiteral* lit = MakeAST(is_global, script, extension, pre_data);
// Check for parse errors.
if (lit == NULL) {
ASSERT(Top::has_pending_exception());
return Handle<JSFunction>::null();
}
// Measure how long it takes to do the compilation; only take the
// rest of the function into account to avoid overlap with the
// parsing statistics.
StatsRate* rate = is_eval
? &Counters::compile_eval
: &Counters::compile;
StatsRateScope timer(rate);
// Compile the code.
Handle<Code> code = MakeCode(lit, script, is_eval);
// Check for stack-overflow exceptions.
if (code.is_null()) {
Top::StackOverflow();
return Handle<JSFunction>::null();
}
if (script->name()->IsString()) {
SmartPointer<char> data =
String::cast(script->name())->ToCString(DISALLOW_NULLS);
LOG(CodeCreateEvent(is_eval ? "Eval" : "Script", *code, *data));
} else {
LOG(CodeCreateEvent(is_eval ? "Eval" : "Script", *code, ""));
}
// Allocate function.
Handle<JSFunction> fun =
Factory::NewFunctionBoilerplate(lit->name(),
lit->materialized_literal_count(),
lit->contains_array_literal(),
code);
CodeGenerator::SetFunctionInfo(fun, lit->scope()->num_parameters(),
RelocInfo::kNoPosition,
lit->start_position(), lit->end_position(),
lit->is_expression(), true, script);
// Hint to the runtime system used when allocating space for initial
// property space by setting the expected number of properties for
// the instances of the function.
SetExpectedNofPropertiesFromEstimate(fun, lit->expected_property_count());
// Notify debugger
Debugger::OnAfterCompile(script, fun);
return fun;
}
static StaticResource<SafeStringInputBuffer> safe_string_input_buffer;
Handle<JSFunction> Compiler::Compile(Handle<String> source,
Handle<Object> script_name,
int line_offset, int column_offset,
v8::Extension* extension,
ScriptDataImpl* input_pre_data) {
Counters::total_load_size.Increment(source->length());
Counters::total_compile_size.Increment(source->length());
// The VM is in the COMPILER state until exiting this function.
VMState state(COMPILER);
// Do a lookup in the compilation cache but not for extensions.
Handle<JSFunction> result;
if (extension == NULL) {
result = CompilationCache::LookupScript(source,
script_name,
line_offset,
column_offset);
}
if (result.is_null()) {
// No cache entry found. Do pre-parsing and compile the script.
ScriptDataImpl* pre_data = input_pre_data;
if (pre_data == NULL && source->length() >= FLAG_min_preparse_length) {
Access<SafeStringInputBuffer> buf(&safe_string_input_buffer);
buf->Reset(source.location());
pre_data = PreParse(buf.value(), extension);
}
// Create a script object describing the script to be compiled.
Handle<Script> script = Factory::NewScript(source);
if (!script_name.is_null()) {
script->set_name(*script_name);
script->set_line_offset(Smi::FromInt(line_offset));
script->set_column_offset(Smi::FromInt(column_offset));
}
// Compile the function and add it to the cache.
result = MakeFunction(true, false, script, extension, pre_data);
if (extension == NULL && !result.is_null()) {
CompilationCache::PutFunction(source, CompilationCache::SCRIPT, result);
}
// Get rid of the pre-parsing data (if necessary).
if (input_pre_data == NULL && pre_data != NULL) {
delete pre_data;
}
}
return result;
}
Handle<JSFunction> Compiler::CompileEval(Handle<String> source,
int line_offset,
bool is_global) {
Counters::total_eval_size.Increment(source->length());
Counters::total_compile_size.Increment(source->length());
// The VM is in the COMPILER state until exiting this function.
VMState state(COMPILER);
CompilationCache::Entry entry = is_global
? CompilationCache::EVAL_GLOBAL
: CompilationCache::EVAL_CONTEXTUAL;
// Do a lookup in the compilation cache; if the entry is not there,
// invoke the compiler and add the result to the cache.
Handle<JSFunction> result = CompilationCache::LookupEval(source, entry);
if (result.is_null()) {
// Create a script object describing the script to be compiled.
Handle<Script> script = Factory::NewScript(source);
script->set_line_offset(Smi::FromInt(line_offset));
result = MakeFunction(is_global, true, script, NULL, NULL);
if (!result.is_null()) {
CompilationCache::PutFunction(source, entry, result);
}
}
return result;
}
bool Compiler::CompileLazy(Handle<SharedFunctionInfo> shared) {
ZoneScope zone_scope(DELETE_ON_EXIT);
// The VM is in the COMPILER state until exiting this function.
VMState state(COMPILER);
// Make sure we have an initial stack limit.
StackGuard guard;
PostponeInterruptsScope postpone;
// Compute name, source code and script data.
Handle<String> name(String::cast(shared->name()));
Handle<Script> script(Script::cast(shared->script()));
int start_position = shared->start_position();
int end_position = shared->end_position();
bool is_expression = shared->is_expression();
Counters::total_compile_size.Increment(end_position - start_position);
// Generate the AST for the lazily compiled function. The AST may be
// NULL in case of parser stack overflow.
FunctionLiteral* lit = MakeLazyAST(script, name,
start_position,
end_position,
is_expression);
// Check for parse errors.
if (lit == NULL) {
ASSERT(Top::has_pending_exception());
return false;
}
// Measure how long it takes to do the lazy compilation; only take
// the rest of the function into account to avoid overlap with the
// lazy parsing statistics.
StatsRateScope timer(&Counters::compile_lazy);
// Compile the code.
Handle<Code> code = MakeCode(lit, script, false);
// Check for stack-overflow exception.
if (code.is_null()) {
Top::StackOverflow();
return false;
}
// Generate the code, update the function info, and return the code.
LOG(CodeCreateEvent("LazyCompile", *code, *lit->name()));
// Update the shared function info with the compiled code.
shared->set_code(*code);
// Set the expected number of properties for instances.
SetExpectedNofPropertiesFromEstimate(shared, lit->expected_property_count());
// Check the function has compiled code.
ASSERT(shared->is_compiled());
return true;
}
} } // namespace v8::internal

View File

@ -1,72 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#ifndef V8_COMPILER_H_
#define V8_COMPILER_H_
#include "parser.h"
namespace v8 { namespace internal {
// The V8 compiler
//
// General strategy: Source code is translated into an anonymous function w/o
// parameters which then can be executed. If the source code contains other
// functions, they will be compiled and allocated as part of the compilation
// of the source code.
// Please note this interface returns function boilerplates.
// This means you need to call Factory::NewFunctionFromBoilerplate
// before you have a real function with context.
class Compiler : public AllStatic {
public:
// All routines return a JSFunction.
// If an error occurs an exception is raised and
// the return handle contains NULL.
// Compile a String source within a context.
static Handle<JSFunction> Compile(Handle<String> source,
Handle<Object> script_name,
int line_offset, int column_offset,
v8::Extension* extension,
ScriptDataImpl* script_Data);
// Compile a String source within a context for Eval.
static Handle<JSFunction> CompileEval(Handle<String> source,
int line_offset,
bool is_global);
// Compile from function info (used for lazy compilation). Returns
// true on success and false if the compilation resulted in a stack
// overflow.
static bool CompileLazy(Handle<SharedFunctionInfo> shared);
};
} } // namespace v8::internal
#endif // V8_COMPILER_H_

View File

@ -1,208 +0,0 @@
// Copyright 2008 the V8 project 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.
#ifndef V8_CONSTANTS_ARM_H_
#define V8_CONSTANTS_ARM_H_
namespace assembler { namespace arm {
// Defines constants and accessor classes to assemble, disassemble and
// simulate ARM instructions.
//
// Constants for specific fields are defined in their respective named enums.
// General constants are in an anonymous enum in class Instr.
typedef unsigned char byte;
enum Condition {
no_condition = -1,
EQ = 0,
NE = 1,
CS = 2,
CC = 3,
MI = 4,
PL = 5,
VS = 6,
VC = 7,
HI = 8,
LS = 9,
GE = 10,
LT = 11,
GT = 12,
LE = 13,
AL = 14,
special_condition = 15
};
enum Opcode {
no_operand = -1,
AND = 0,
EOR = 1,
SUB = 2,
RSB = 3,
ADD = 4,
ADC = 5,
SBC = 6,
RSC = 7,
TST = 8,
TEQ = 9,
CMP = 10,
CMN = 11,
ORR = 12,
MOV = 13,
BIC = 14,
MVN = 15
};
enum Shift {
no_shift = -1,
LSL = 0,
LSR = 1,
ASR = 2,
ROR = 3
};
enum SoftwareInterruptCodes {
// transition to C code
call_rt_r5 = 0x10,
call_rt_r2 = 0x11,
// break point
break_point = 0x20
};
typedef int32_t instr_t;
// The class Instr enables access to individual fields defined in the ARM
// architecture.
class Instr {
public:
enum {
kInstrSize = 4,
kPCReadOffset = 8
};
// Get the raw instruction bits
inline instr_t InstructionBits() const {
return *reinterpret_cast<const instr_t*>(this);
}
inline void SetInstructionBits(instr_t value) {
*reinterpret_cast<instr_t*>(this) = value;
}
inline int Bit(int nr) const {
return (InstructionBits() >> nr) & 1;
}
inline int Bits(int hi, int lo) const {
return (InstructionBits() >> lo) & ((2 << (hi - lo)) - 1);
}
// Accessors for the different named fields used in the ARM encoding.
// Generally applicable fields
inline Condition ConditionField() const {
return static_cast<Condition>(Bits(31, 28));
}
inline int TypeField() const { return Bits(27, 25); }
inline int RnField() const { return Bits(19, 16); }
inline int RdField() const { return Bits(15, 12); }
// Fields used in Data processing instructions
inline Opcode OpcodeField() const {
return static_cast<Opcode>(Bits(24, 21));
}
inline int SField() const { return Bit(20); }
// with register
inline int RmField() const { return Bits(3, 0); }
inline Shift ShiftField() const { return static_cast<Shift>(Bits(6, 5)); }
inline int RegShiftField() const { return Bit(4); }
inline int RsField() const { return Bits(11, 8); }
inline int ShiftAmountField() const { return Bits(11, 7); }
// with immediate
inline int RotateField() const { return Bits(11, 8); }
inline int Immed8Field() const { return Bits(7, 0); }
// Fields used in Load/Store instructions
inline int PUField() const { return Bits(24, 23); }
inline int BField() const { return Bit(22); }
inline int WField() const { return Bit(21); }
inline int LField() const { return Bit(20); }
// with register uses same fields as Data processing instructions above
// with immediate
inline int Offset12Field() const { return Bits(11, 0); }
// multiple
inline int RlistField() const { return Bits(15, 0); }
// extra loads and stores
inline int SignField() const { return Bit(6); }
inline int HField() const { return Bit(5); }
inline int ImmedHField() const { return Bits(11, 8); }
inline int ImmedLField() const { return Bits(3, 0); }
// Fields used in Branch instructions
inline int LinkField() const { return Bit(24); }
inline int SImmed24Field() const { return ((InstructionBits() << 8) >> 8); }
// Fields used in Software interrupt instructions
inline SoftwareInterruptCodes SwiField() const {
return static_cast<SoftwareInterruptCodes>(Bits(23, 0));
}
// Test for special encodings of type 0 instructions (extra loads and stores,
// as well as multiplications).
inline bool IsSpecialType0() const { return (Bit(7) == 1) && (Bit(4) == 1); }
// Special accessors that test for existence of a value.
inline bool HasS() const { return SField() == 1; }
inline bool HasB() const { return BField() == 1; }
inline bool HasW() const { return WField() == 1; }
inline bool HasL() const { return LField() == 1; }
inline bool HasSign() const { return SignField() == 1; }
inline bool HasH() const { return HField() == 1; }
inline bool HasLink() const { return LinkField() == 1; }
// Instructions are read of out a code stream. The only way to get a
// reference to an instruction is to convert a pointer. There is no way
// to allocate or create instances of class Instr.
// Use the At(pc) function to create references to Instr.
static Instr* At(byte* pc) { return reinterpret_cast<Instr*>(pc); }
private:
// We need to prevent the creation of instances of class Instr.
DISALLOW_IMPLICIT_CONSTRUCTORS(Instr);
};
} } // namespace assembler::arm
#endif // V8_CONSTANTS_ARM_H_

View File

@ -1,218 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#include "v8.h"
#include "bootstrapper.h"
#include "debug.h"
#include "scopeinfo.h"
namespace v8 { namespace internal {
JSBuiltinsObject* Context::builtins() {
GlobalObject* object = global();
if (object->IsJSGlobalObject()) {
return JSGlobalObject::cast(object)->builtins();
} else {
ASSERT(object->IsJSBuiltinsObject());
return JSBuiltinsObject::cast(object);
}
}
Context* Context::global_context() {
// Fast case: the global object for this context has been set. In
// that case, the global object has a direct pointer to the global
// context.
if (global()->IsGlobalObject()) {
return global()->global_context();
}
// During bootstrapping, the global object might not be set and we
// have to search the context chain to find the global context.
Context* current = this;
while (!current->IsGlobalContext()) {
current = Context::cast(JSFunction::cast(current->closure())->context());
}
return current;
}
JSObject* Context::global_proxy() {
return global_context()->global_proxy_object();
}
void Context::set_global_proxy(JSObject* object) {
global_context()->set_global_proxy_object(object);
}
Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
int* index_, PropertyAttributes* attributes) {
Handle<Context> context(this);
// The context must be in frame slot 0 (if not debugging).
if (kDebug && !Debug::InDebugger()) {
StackFrameLocator locator;
ASSERT(context->fcontext() ==
Context::cast(
locator.FindJavaScriptFrame(0)->context())->fcontext());
}
bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0;
*index_ = -1;
*attributes = ABSENT;
if (FLAG_trace_contexts) {
PrintF("Context::Lookup(");
name->ShortPrint();
PrintF(")\n");
}
do {
if (FLAG_trace_contexts) {
PrintF(" - looking in context %p", *context);
if (context->IsGlobalContext()) PrintF(" (global context)");
PrintF("\n");
}
// check extension/with object
if (context->has_extension()) {
Handle<JSObject> extension = Handle<JSObject>(context->extension());
if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0) {
*attributes = extension->GetLocalPropertyAttribute(*name);
} else {
*attributes = extension->GetPropertyAttribute(*name);
}
if (*attributes != ABSENT) {
// property found
if (FLAG_trace_contexts) {
PrintF("=> found property in context object %p\n", *extension);
}
return extension;
}
}
if (context->is_function_context()) {
// we have context-local slots
// check non-parameter locals in context
Handle<Code> code(context->closure()->code());
Variable::Mode mode;
int index = ScopeInfo<>::ContextSlotIndex(*code, *name, &mode);
ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS);
if (index >= 0) {
// slot found
if (FLAG_trace_contexts) {
PrintF("=> found local in context slot %d (mode = %d)\n",
index, mode);
}
*index_ = index;
// Note: Fixed context slots are statically allocated by the compiler.
// Statically allocated variables always have a statically known mode,
// which is the mode with which they were declared when added to the
// scope. Thus, the DYNAMIC mode (which corresponds to dynamically
// declared variables that were introduced through declaration nodes)
// must not appear here.
switch (mode) {
case Variable::INTERNAL : // fall through
case Variable::VAR : *attributes = NONE; break;
case Variable::CONST : *attributes = READ_ONLY; break;
case Variable::DYNAMIC : UNREACHABLE(); break;
case Variable::TEMPORARY: UNREACHABLE(); break;
}
return context;
}
// check parameter locals in context
int param_index = ScopeInfo<>::ParameterIndex(*code, *name);
if (param_index >= 0) {
// slot found
int index =
ScopeInfo<>::ContextSlotIndex(*code,
Heap::arguments_shadow_symbol(),
NULL);
ASSERT(index >= 0); // arguments must exist and be in the heap context
Handle<JSObject> arguments(JSObject::cast(context->get(index)));
ASSERT(arguments->HasLocalProperty(Heap::length_symbol()));
if (FLAG_trace_contexts) {
PrintF("=> found parameter %d in arguments object\n", param_index);
}
*index_ = param_index;
*attributes = NONE;
return arguments;
}
// check intermediate context (holding only the function name variable)
if (follow_context_chain) {
int index = ScopeInfo<>::FunctionContextSlotIndex(*code, *name);
if (index >= 0) {
// slot found
if (FLAG_trace_contexts) {
PrintF("=> found intermediate function in context slot %d\n",
index);
}
*index_ = index;
*attributes = READ_ONLY;
return context;
}
}
}
// proceed with enclosing context
if (context->IsGlobalContext()) {
follow_context_chain = false;
} else if (context->is_function_context()) {
context = Handle<Context>(Context::cast(context->closure()->context()));
} else {
context = Handle<Context>(context->previous());
}
} while (follow_context_chain);
// slot not found
if (FLAG_trace_contexts) {
PrintF("=> no property/slot found\n");
}
return Handle<Object>::null();
}
#ifdef DEBUG
bool Context::IsBootstrappingOrContext(Object* object) {
// During bootstrapping we allow all objects to pass as
// contexts. This is necessary to fix circular dependencies.
return Bootstrapper::IsActive() || object->IsContext();
}
bool Context::IsBootstrappingOrGlobalObject(Object* object) {
// During bootstrapping we allow all objects to pass as global
// objects. This is necessary to fix circular dependencies.
return Bootstrapper::IsActive() || object->IsGlobalObject();
}
#endif
} } // namespace v8::internal

View File

@ -1,322 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#ifndef V8_CONTEXTS_H_
#define V8_CONTEXTS_H_
namespace v8 { namespace internal {
enum ContextLookupFlags {
FOLLOW_CONTEXT_CHAIN = 1,
FOLLOW_PROTOTYPE_CHAIN = 2,
DONT_FOLLOW_CHAINS = 0,
FOLLOW_CHAINS = FOLLOW_CONTEXT_CHAIN | FOLLOW_PROTOTYPE_CHAIN
};
// Heap-allocated activation contexts.
//
// Contexts are implemented as FixedArray objects; the Context
// class is a convenience interface casted on a FixedArray object.
//
// Note: Context must have no virtual functions and Context objects
// must always be allocated via Heap::AllocateContext() or
// Factory::NewContext.
// Comment for special_function_table:
// Table for providing optimized/specialized functions.
// The array contains triplets [object, general_function, optimized_function].
// Primarily added to support built-in optimized variants of
// Array.prototype.{push,pop}.
#define GLOBAL_CONTEXT_FIELDS(V) \
V(GLOBAL_PROXY_INDEX, JSObject, global_proxy_object) \
V(SECURITY_TOKEN_INDEX, Object, security_token) \
V(BOOLEAN_FUNCTION_INDEX, JSFunction, boolean_function) \
V(NUMBER_FUNCTION_INDEX, JSFunction, number_function) \
V(STRING_FUNCTION_INDEX, JSFunction, string_function) \
V(OBJECT_FUNCTION_INDEX, JSFunction, object_function) \
V(ARRAY_FUNCTION_INDEX, JSFunction, array_function) \
V(DATE_FUNCTION_INDEX, JSFunction, date_function) \
V(REGEXP_FUNCTION_INDEX, JSFunction, regexp_function) \
V(INITIAL_OBJECT_PROTOTYPE_INDEX, JSObject, initial_object_prototype) \
V(CREATE_DATE_FUN_INDEX, JSFunction, create_date_fun) \
V(TO_NUMBER_FUN_INDEX, JSFunction, to_number_fun) \
V(TO_STRING_FUN_INDEX, JSFunction, to_string_fun) \
V(TO_DETAIL_STRING_FUN_INDEX, JSFunction, to_detail_string_fun) \
V(TO_OBJECT_FUN_INDEX, JSFunction, to_object_fun) \
V(TO_INTEGER_FUN_INDEX, JSFunction, to_integer_fun) \
V(TO_UINT32_FUN_INDEX, JSFunction, to_uint32_fun) \
V(TO_INT32_FUN_INDEX, JSFunction, to_int32_fun) \
V(TO_BOOLEAN_FUN_INDEX, JSFunction, to_boolean_fun) \
V(INSTANTIATE_FUN_INDEX, JSFunction, instantiate_fun) \
V(CONFIGURE_INSTANCE_FUN_INDEX, JSFunction, configure_instance_fun) \
V(FUNCTION_MAP_INDEX, Map, function_map) \
V(FUNCTION_INSTANCE_MAP_INDEX, Map, function_instance_map) \
V(JS_ARRAY_MAP_INDEX, Map, js_array_map)\
V(SPECIAL_FUNCTION_TABLE_INDEX, FixedArray, special_function_table) \
V(ARGUMENTS_BOILERPLATE_INDEX, JSObject, arguments_boilerplate) \
V(MESSAGE_LISTENERS_INDEX, JSObject, message_listeners) \
V(DEBUG_EVENT_LISTENERS_INDEX, JSObject, debug_event_listeners) \
V(MAKE_MESSAGE_FUN_INDEX, JSFunction, make_message_fun) \
V(GET_STACK_TRACE_LINE_INDEX, JSFunction, get_stack_trace_line_fun) \
V(CONFIGURE_GLOBAL_INDEX, JSFunction, configure_global_fun) \
V(FUNCTION_CACHE_INDEX, JSObject, function_cache) \
V(RUNTIME_CONTEXT_INDEX, Context, runtime_context) \
V(CALL_AS_FUNCTION_DELEGATE_INDEX, JSFunction, call_as_function_delegate) \
V(EMPTY_SCRIPT_INDEX, Script, empty_script) \
V(SCRIPT_FUNCTION_INDEX, JSFunction, script_function) \
V(CONTEXT_EXTENSION_FUNCTION_INDEX, JSFunction, context_extension_function) \
V(OUT_OF_MEMORY_INDEX, Object, out_of_memory) \
V(MAP_CACHE_INDEX, Object, map_cache)
// JSFunctions are pairs (context, function code), sometimes also called
// closures. A Context object is used to represent function contexts and
// dynamically pushed 'with' contexts (or 'scopes' in ECMA-262 speak).
//
// At runtime, the contexts build a stack in parallel to the execution
// stack, with the top-most context being the current context. All contexts
// have the following slots:
//
// [ closure ] This is the current function. It is the same for all
// contexts inside a function. It provides access to the
// incoming context (i.e., the outer context, which may
// or may not become the current function's context), and
// it provides access to the functions code and thus it's
// scope information, which in turn contains the names of
// statically allocated context slots. The names are needed
// for dynamic lookups in the presence of 'with' or 'eval'.
//
// [ fcontext ] A pointer to the innermost enclosing function context.
// It is the same for all contexts *allocated* inside a
// function, and the function context's fcontext points
// to itself. It is only needed for fast access of the
// function context (used for declarations, and static
// context slot access).
//
// [ previous ] A pointer to the previous context. It is NULL for
// function contexts, and non-NULL for 'with' contexts.
// Used to implement the 'with' statement.
//
// [ extension ] A pointer to an extension JSObject, or NULL. Used to
// implement 'with' statements and dynamic declarations
// (through 'eval'). The object in a 'with' statement is
// stored in the extension slot of a 'with' context.
// Dynamically declared variables/functions are also added
// to lazily allocated extension object. Context::Lookup
// searches the extension object for properties.
//
// [ global ] A pointer to the global object. Provided for quick
// access to the global object from inside the code (since
// we always have a context pointer).
//
// In addition, function contexts may have statically allocated context slots
// to store local variables/functions that are accessed from inner functions
// (via static context addresses) or through 'eval' (dynamic context lookups).
// Finally, the global context contains additional slots for fast access to
// global properties.
//
// We may be able to simplify the implementation:
//
// - We may be able to get rid of 'fcontext': We can always use the fact that
// previous == NULL for function contexts and so we can search for them. They
// are only needed when doing dynamic declarations, and the context chains
// tend to be very very short (depth of nesting of 'with' statements). At
// the moment we also use it in generated code for context slot accesses -
// and there we don't want a loop because of code bloat - but we may not
// need it there after all (see comment in codegen_*.cc).
//
// - If we cannot get rid of fcontext, consider making 'previous' never NULL
// except for the global context. This could simplify Context::Lookup.
class Context: public FixedArray {
public:
// Conversions.
static Context* cast(Object* context) {
ASSERT(context->IsContext());
return reinterpret_cast<Context*>(context);
}
// The default context slot layout; indices are FixedArray slot indices.
enum {
// These slots are in all contexts.
CLOSURE_INDEX,
FCONTEXT_INDEX,
PREVIOUS_INDEX,
EXTENSION_INDEX,
GLOBAL_INDEX,
MIN_CONTEXT_SLOTS,
// These slots are only in global contexts.
GLOBAL_PROXY_INDEX = MIN_CONTEXT_SLOTS,
SECURITY_TOKEN_INDEX,
ARGUMENTS_BOILERPLATE_INDEX,
JS_ARRAY_MAP_INDEX,
FUNCTION_MAP_INDEX,
FUNCTION_INSTANCE_MAP_INDEX,
INITIAL_OBJECT_PROTOTYPE_INDEX,
BOOLEAN_FUNCTION_INDEX,
NUMBER_FUNCTION_INDEX,
STRING_FUNCTION_INDEX,
OBJECT_FUNCTION_INDEX,
ARRAY_FUNCTION_INDEX,
DATE_FUNCTION_INDEX,
REGEXP_FUNCTION_INDEX,
CREATE_DATE_FUN_INDEX,
TO_NUMBER_FUN_INDEX,
TO_STRING_FUN_INDEX,
TO_DETAIL_STRING_FUN_INDEX,
TO_OBJECT_FUN_INDEX,
TO_INTEGER_FUN_INDEX,
TO_UINT32_FUN_INDEX,
TO_INT32_FUN_INDEX,
TO_BOOLEAN_FUN_INDEX,
INSTANTIATE_FUN_INDEX,
CONFIGURE_INSTANCE_FUN_INDEX,
SPECIAL_FUNCTION_TABLE_INDEX,
MESSAGE_LISTENERS_INDEX,
DEBUG_EVENT_LISTENERS_INDEX,
MAKE_MESSAGE_FUN_INDEX,
GET_STACK_TRACE_LINE_INDEX,
CONFIGURE_GLOBAL_INDEX,
FUNCTION_CACHE_INDEX,
RUNTIME_CONTEXT_INDEX,
CALL_AS_FUNCTION_DELEGATE_INDEX,
EMPTY_SCRIPT_INDEX,
SCRIPT_FUNCTION_INDEX,
CONTEXT_EXTENSION_FUNCTION_INDEX,
OUT_OF_MEMORY_INDEX,
MAP_CACHE_INDEX,
GLOBAL_CONTEXT_SLOTS
};
// Direct slot access.
JSFunction* closure() { return JSFunction::cast(get(CLOSURE_INDEX)); }
void set_closure(JSFunction* closure) { set(CLOSURE_INDEX, closure); }
Context* fcontext() { return Context::cast(get(FCONTEXT_INDEX)); }
void set_fcontext(Context* context) { set(FCONTEXT_INDEX, context); }
Context* previous() {
Object* result = unchecked_previous();
ASSERT(IsBootstrappingOrContext(result));
return reinterpret_cast<Context*>(result);
}
void set_previous(Context* context) { set(PREVIOUS_INDEX, context); }
bool has_extension() { return unchecked_extension() != NULL; }
JSObject* extension() { return JSObject::cast(unchecked_extension()); }
void set_extension(JSObject* object) { set(EXTENSION_INDEX, object); }
GlobalObject* global() {
Object* result = get(GLOBAL_INDEX);
ASSERT(IsBootstrappingOrGlobalObject(result));
return reinterpret_cast<GlobalObject*>(result);
}
void set_global(GlobalObject* global) { set(GLOBAL_INDEX, global); }
// Returns a JSGlobalProxy object or null.
JSObject* global_proxy();
void set_global_proxy(JSObject* global);
// The builtins object.
JSBuiltinsObject* builtins();
// Compute the global context by traversing the context chain.
Context* global_context();
// Tells if this is a function context (as opposed to a 'with' context).
bool is_function_context() { return unchecked_previous() == NULL; }
// Tells whether the global context is marked with out of memory.
bool has_out_of_memory() {
return global_context()->out_of_memory() == Heap::true_value();
}
// Mark the global context with out of memory.
void mark_out_of_memory() {
global_context()->set_out_of_memory(Heap::true_value());
}
#define GLOBAL_CONTEXT_FIELD_ACCESSORS(index, type, name) \
void set_##name(type* value) { \
ASSERT(IsGlobalContext()); \
set(index, value); \
} \
type* name() { \
ASSERT(IsGlobalContext()); \
return type::cast(get(index)); \
}
GLOBAL_CONTEXT_FIELDS(GLOBAL_CONTEXT_FIELD_ACCESSORS)
#undef GLOBAL_CONTEXT_FIELD_ACCESSORS
// Lookup the the slot called name, starting with the current context.
// There are 4 possible outcomes:
//
// 1) index_ >= 0 && result->IsContext():
// most common case, the result is a Context, and index is the
// context slot index, and the slot exists.
// attributes == READ_ONLY for the function name variable, NONE otherwise.
//
// 2) index_ >= 0 && result->IsJSObject():
// the result is the JSObject arguments object, the index is the parameter
// index, i.e., key into the arguments object, and the property exists.
// attributes != ABSENT.
//
// 3) index_ < 0 && result->IsJSObject():
// the result is the JSObject extension context or the global object,
// and the name is the property name, and the property exists.
// attributes != ABSENT.
//
// 4) index_ < 0 && result.is_null():
// there was no context found with the corresponding property.
// attributes == ABSENT.
Handle<Object> Lookup(Handle<String> name, ContextLookupFlags flags,
int* index_, PropertyAttributes* attributes);
// Code generation support.
static int SlotOffset(int index) {
return kHeaderSize + index * kPointerSize - kHeapObjectTag;
}
private:
// Unchecked access to the slots.
Object* unchecked_previous() { return get(PREVIOUS_INDEX); }
Object* unchecked_extension() { return get(EXTENSION_INDEX); }
#ifdef DEBUG
// Bootstrapping-aware type checks.
static bool IsBootstrappingOrContext(Object* object);
static bool IsBootstrappingOrGlobalObject(Object* object);
#endif
};
} } // namespace v8::internal
#endif // V8_CONTEXTS_H_

View File

@ -1,93 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#ifndef V8_CONVERSIONS_INL_H_
#define V8_CONVERSIONS_INL_H_
#include <math.h>
#include <float.h> // required for DBL_MAX and on Win32 for finite()
// ----------------------------------------------------------------------------
// Extra POSIX/ANSI functions for Win32/MSVC.
#include "conversions.h"
#include "platform.h"
namespace v8 { namespace internal {
// The fast double-to-int conversion routine does not guarantee
// rounding towards zero.
static inline int FastD2I(double x) {
#ifdef __USE_ISOC99
// The ISO C99 standard defines the lrint() function which rounds a
// double to an integer according to the current rounding direction.
return lrint(x);
#else
// This is incredibly slow on Intel x86. The reason is that rounding
// towards zero is implied by the C standard. This means that the
// status register of the FPU has to be changed with the 'fldcw'
// instruction. This completely stalls the pipeline and takes many
// hundreds of clock cycles.
return static_cast<int>(x);
#endif
}
static inline double DoubleToInteger(double x) {
if (isnan(x)) return 0;
if (!isfinite(x) || x == 0) return x;
return (x >= 0) ? floor(x) : ceil(x);
}
int32_t NumberToInt32(Object* number) {
if (number->IsSmi()) return Smi::cast(number)->value();
return DoubleToInt32(number->Number());
}
uint32_t NumberToUint32(Object* number) {
if (number->IsSmi()) return Smi::cast(number)->value();
return DoubleToUint32(number->Number());
}
int32_t DoubleToInt32(double x) {
int32_t i = FastD2I(x);
if (FastI2D(i) == x) return i;
static const double two32 = 4294967296.0;
static const double two31 = 2147483648.0;
if (!isfinite(x) || x == 0) return 0;
if (x < 0 || x >= two32) x = fmod(x, two32);
x = (x >= 0) ? floor(x) : ceil(x) + two32;
return (int32_t) ((x >= two31) ? x - two32 : x);
}
} } // namespace v8::internal
#endif // V8_CONVERSIONS_INL_H_

View File

@ -1,702 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#include <stdarg.h>
#include "v8.h"
#include "conversions-inl.h"
#include "factory.h"
#include "scanner.h"
namespace v8 { namespace internal {
int HexValue(uc32 c) {
if ('0' <= c && c <= '9')
return c - '0';
if ('a' <= c && c <= 'f')
return c - 'a' + 10;
if ('A' <= c && c <= 'F')
return c - 'A' + 10;
return -1;
}
// Provide a common interface to getting a character at a certain
// index from a char* or a String object.
static inline int GetChar(const char* str, int index) {
ASSERT(index >= 0 && index < static_cast<int>(strlen(str)));
return str[index];
}
static inline int GetChar(String* str, int index) {
return str->Get(index);
}
static inline int GetLength(const char* str) {
return strlen(str);
}
static inline int GetLength(String* str) {
return str->length();
}
static inline const char* GetCString(const char* str, int index) {
return str + index;
}
static inline const char* GetCString(String* str, int index) {
char* result = NewArray<char>(str->length() + 1);
for (int i = index; i < str->length(); i++) {
if (str->Get(i) <= 127) {
result[i - index] = static_cast<char>(str->Get(i));
} else {
result[i - index] = 127; // Force number parsing to fail.
}
}
result[str->length() - index] = '\0';
return result;
}
static inline void ReleaseCString(const char* original, const char* str) {
}
static inline void ReleaseCString(String* original, const char* str) {
DeleteArray(const_cast<char *>(str));
}
static inline bool IsSpace(const char* str, int index) {
ASSERT(index >= 0 && index < static_cast<int>(strlen(str)));
return Scanner::kIsWhiteSpace.get(str[index]);
}
static inline bool IsSpace(String* str, int index) {
return Scanner::kIsWhiteSpace.get(str->Get(index));
}
static inline bool SubStringEquals(const char* str,
int index,
const char* other) {
return strncmp(str + index, other, strlen(other)) != 0;
}
static inline bool SubStringEquals(String* str, int index, const char* other) {
HandleScope scope;
int len = strlen(other);
int end = index + len < str->length() ? index + len : str->length();
Handle<String> slice =
Factory::NewStringSlice(Handle<String>(str), index, end);
return slice->IsEqualTo(Vector<const char>(other, len));
}
// Check if a string should be parsed as an octal number. The string
// can be either a char* or a String*.
template<class S>
static bool ShouldParseOctal(S* s, int i) {
int index = i;
int len = GetLength(s);
if (index < len && GetChar(s, index) != '0') return false;
// If the first real character (following '0') is not an octal
// digit, bail out early. This also takes care of numbers of the
// forms 0.xxx and 0exxx by not allowing the first 0 to be
// interpreted as an octal.
index++;
if (index < len) {
int d = GetChar(s, index) - '0';
if (d < 0 || d > 7) return false;
} else {
return false;
}
// Traverse all digits (including the first). If there is an octal
// prefix which is not a part of a longer decimal prefix, we return
// true. Otherwise, false is returned.
while (index < len) {
int d = GetChar(s, index++) - '0';
if (d == 8 || d == 9) return false;
if (d < 0 || d > 7) return true;
}
return true;
}
extern "C" double gay_strtod(const char* s00, const char** se);
// Parse an int from a string starting a given index and in a given
// radix. The string can be either a char* or a String*.
template <class S>
static int InternalStringToInt(S* s, int i, int radix, double* value) {
int len = GetLength(s);
// Setup limits for computing the value.
ASSERT(2 <= radix && radix <= 36);
int lim_0 = '0' + (radix < 10 ? radix : 10);
int lim_a = 'a' + (radix - 10);
int lim_A = 'A' + (radix - 10);
// NOTE: The code for computing the value may seem a bit complex at
// first glance. It is structured to use 32-bit multiply-and-add
// loops as long as possible to avoid loosing precision.
double v = 0.0;
int j;
for (j = i; j < len;) {
// Parse the longest part of the string starting at index j
// possible while keeping the multiplier, and thus the part
// itself, within 32 bits.
uint32_t part = 0, multiplier = 1;
int k;
for (k = j; k < len; k++) {
int c = GetChar(s, k);
if (c >= '0' && c < lim_0) {
c = c - '0';
} else if (c >= 'a' && c < lim_a) {
c = c - 'a' + 10;
} else if (c >= 'A' && c < lim_A) {
c = c - 'A' + 10;
} else {
break;
}
// Update the value of the part as long as the multiplier fits
// in 32 bits. When we can't guarantee that the next iteration
// will not overflow the multiplier, we stop parsing the part
// by leaving the loop.
static const uint32_t kMaximumMultiplier = 0xffffffffU / 36;
uint32_t m = multiplier * radix;
if (m > kMaximumMultiplier) break;
part = part * radix + c;
multiplier = m;
ASSERT(multiplier > part);
}
// Compute the number of part digits. If no digits were parsed;
// we're done parsing the entire string.
int digits = k - j;
if (digits == 0) break;
// Update the value and skip the part in the string.
ASSERT(multiplier ==
pow(static_cast<double>(radix), static_cast<double>(digits)));
v = v * multiplier + part;
j = k;
}
// If the resulting value is larger than 2^53 the value does not fit
// in the mantissa of the double and there is a loss of precision.
// When the value is larger than 2^53 the rounding depends on the
// code generation. If the code generator spills the double value
// it uses 64 bits and if it does not it uses 80 bits.
//
// If there is a potential for overflow we resort to strtod for
// radix 10 numbers to get higher precision. For numbers in another
// radix we live with the loss of precision.
static const double kPreciseConversionLimit = 9007199254740992.0;
if (radix == 10 && v > kPreciseConversionLimit) {
const char* cstr = GetCString(s, i);
const char* end;
v = gay_strtod(cstr, &end);
ReleaseCString(s, cstr);
}
*value = v;
return j;
}
int StringToInt(String* str, int index, int radix, double* value) {
return InternalStringToInt(str, index, radix, value);
}
int StringToInt(const char* str, int index, int radix, double* value) {
return InternalStringToInt(const_cast<char*>(str), index, radix, value);
}
static const double JUNK_STRING_VALUE = OS::nan_value();
// Convert a string to a double value. The string can be either a
// char* or a String*.
template<class S>
static double InternalStringToDouble(S* str,
int flags,
double empty_string_val) {
double result = 0.0;
int index = 0;
int len = GetLength(str);
// Skip leading spaces.
while ((index < len) && IsSpace(str, index)) index++;
// Is the string empty?
if (index >= len) return empty_string_val;
// Get the first character.
uint16_t first = GetChar(str, index);
// Numbers can only start with '-', '+', '.', 'I' (Infinity), or a digit.
if (first != '-' && first != '+' && first != '.' && first != 'I' &&
(first > '9' || first < '0')) {
return JUNK_STRING_VALUE;
}
// Compute sign of result based on first character.
int sign = 1;
if (first == '-') {
sign = -1;
index++;
// String only containing a '-' are junk chars.
if (index == len) return JUNK_STRING_VALUE;
}
// do we have a hex number?
// (since the string is 0-terminated, it's ok to look one char beyond the end)
if ((flags & ALLOW_HEX) != 0 &&
(index + 1) < len &&
GetChar(str, index) == '0' &&
(GetChar(str, index + 1) == 'x' || GetChar(str, index + 1) == 'X')) {
index += 2;
index = StringToInt(str, index, 16, &result);
} else if ((flags & ALLOW_OCTALS) != 0 && ShouldParseOctal(str, index)) {
// NOTE: We optimistically try to parse the number as an octal (if
// we're allowed to), even though this is not as dictated by
// ECMA-262. The reason for doing this is compatibility with IE and
// Firefox.
index = StringToInt(str, index, 8, &result);
} else {
const char* cstr = GetCString(str, index);
const char* end;
// Optimistically parse the number and then, if that fails,
// check if it might have been {+,-,}Infinity.
result = gay_strtod(cstr, &end);
ReleaseCString(str, cstr);
if (result != 0.0 || end != cstr) {
// It appears that strtod worked
index += end - cstr;
} else {
// Check for {+,-,}Infinity
bool is_negative = (GetChar(str, index) == '-');
if (GetChar(str, index) == '+' || GetChar(str, index) == '-')
index++;
if (!SubStringEquals(str, index, "Infinity"))
return JUNK_STRING_VALUE;
result = is_negative ? -INFINITY : INFINITY;
index += 8;
}
}
if ((flags & ALLOW_TRAILING_JUNK) == 0) {
// skip trailing spaces
while ((index < len) && IsSpace(str, index)) index++;
// string ending with junk?
if (index < len) return JUNK_STRING_VALUE;
}
return sign * result;
}
double StringToDouble(String* str, int flags, double empty_string_val) {
return InternalStringToDouble(str, flags, empty_string_val);
}
double StringToDouble(const char* str, int flags, double empty_string_val) {
return InternalStringToDouble(str, flags, empty_string_val);
}
extern "C" char* dtoa(double d, int mode, int ndigits,
int* decpt, int* sign, char** rve);
extern "C" void freedtoa(char* s);
const char* DoubleToCString(double v, Vector<char> buffer) {
StringBuilder builder(buffer.start(), buffer.length());
switch (fpclassify(v)) {
case FP_NAN:
builder.AddString("NaN");
break;
case FP_INFINITE:
if (v < 0.0) {
builder.AddString("-Infinity");
} else {
builder.AddString("Infinity");
}
break;
case FP_ZERO:
builder.AddCharacter('0');
break;
default: {
int decimal_point;
int sign;
char* decimal_rep = dtoa(v, 0, 0, &decimal_point, &sign, NULL);
int length = strlen(decimal_rep);
if (sign) builder.AddCharacter('-');
if (length <= decimal_point && decimal_point <= 21) {
// ECMA-262 section 9.8.1 step 6.
builder.AddString(decimal_rep);
builder.AddPadding('0', decimal_point - length);
} else if (0 < decimal_point && decimal_point <= 21) {
// ECMA-262 section 9.8.1 step 7.
builder.AddSubstring(decimal_rep, decimal_point);
builder.AddCharacter('.');
builder.AddString(decimal_rep + decimal_point);
} else if (decimal_point <= 0 && decimal_point > -6) {
// ECMA-262 section 9.8.1 step 8.
builder.AddString("0.");
builder.AddPadding('0', -decimal_point);
builder.AddString(decimal_rep);
} else {
// ECMA-262 section 9.8.1 step 9 and 10 combined.
builder.AddCharacter(decimal_rep[0]);
if (length != 1) {
builder.AddCharacter('.');
builder.AddString(decimal_rep + 1);
}
builder.AddCharacter('e');
builder.AddCharacter((decimal_point >= 0) ? '+' : '-');
int exponent = decimal_point - 1;
if (exponent < 0) exponent = -exponent;
builder.AddFormatted("%d", exponent);
}
freedtoa(decimal_rep);
}
}
return builder.Finalize();
}
const char* IntToCString(int n, Vector<char> buffer) {
bool negative = false;
if (n < 0) {
// We must not negate the most negative int.
if (n == kMinInt) return DoubleToCString(n, buffer);
negative = true;
n = -n;
}
// Build the string backwards from the least significant digit.
int i = buffer.length();
buffer[--i] = '\0';
do {
buffer[--i] = '0' + (n % 10);
n /= 10;
} while (n);
if (negative) buffer[--i] = '-';
return buffer.start() + i;
}
char* DoubleToFixedCString(double value, int f) {
ASSERT(f >= 0);
bool negative = false;
double abs_value = value;
if (value < 0) {
abs_value = -value;
negative = true;
}
if (abs_value >= 1e21) {
char arr[100];
Vector<char> buffer(arr, ARRAY_SIZE(arr));
return StrDup(DoubleToCString(value, buffer));
}
// Find a sufficiently precise decimal representation of n.
int decimal_point;
int sign;
char* decimal_rep = dtoa(abs_value, 3, f, &decimal_point, &sign, NULL);
int decimal_rep_length = strlen(decimal_rep);
// Create a representation that is padded with zeros if needed.
int zero_prefix_length = 0;
int zero_postfix_length = 0;
if (decimal_point <= 0) {
zero_prefix_length = -decimal_point + 1;
decimal_point = 1;
}
if (zero_prefix_length + decimal_rep_length < decimal_point + f) {
zero_postfix_length = decimal_point + f - decimal_rep_length -
zero_prefix_length;
}
unsigned rep_length =
zero_prefix_length + decimal_rep_length + zero_postfix_length;
StringBuilder rep_builder(rep_length + 1);
rep_builder.AddPadding('0', zero_prefix_length);
rep_builder.AddString(decimal_rep);
rep_builder.AddPadding('0', zero_postfix_length);
char* rep = rep_builder.Finalize();
freedtoa(decimal_rep);
// Create the result string by appending a minus and putting in a
// decimal point if needed.
unsigned result_size = decimal_point + f + 2;
StringBuilder builder(result_size + 1);
if (negative) builder.AddCharacter('-');
builder.AddSubstring(rep, decimal_point);
if (f > 0) {
builder.AddCharacter('.');
builder.AddSubstring(rep + decimal_point, f);
}
DeleteArray(rep);
return builder.Finalize();
}
static char* CreateExponentialRepresentation(char* decimal_rep,
int exponent,
bool negative,
int significant_digits) {
bool negative_exponent = false;
if (exponent < 0) {
negative_exponent = true;
exponent = -exponent;
}
// Leave room in the result for appending a minus, for a period, the
// letter 'e', a minus or a plus depending on the exponent, and a
// three digit exponent.
unsigned result_size = significant_digits + 7;
StringBuilder builder(result_size + 1);
if (negative) builder.AddCharacter('-');
builder.AddCharacter(decimal_rep[0]);
if (significant_digits != 1) {
builder.AddCharacter('.');
builder.AddString(decimal_rep + 1);
builder.AddPadding('0', significant_digits - strlen(decimal_rep));
}
builder.AddCharacter('e');
builder.AddCharacter(negative_exponent ? '-' : '+');
builder.AddFormatted("%d", exponent);
return builder.Finalize();
}
char* DoubleToExponentialCString(double value, int f) {
// f might be -1 to signal that f was undefined in JavaScript.
ASSERT(f >= -1 && f <= 20);
bool negative = false;
if (value < 0) {
value = -value;
negative = true;
}
// Find a sufficiently precise decimal representation of n.
int decimal_point;
int sign;
char* decimal_rep = NULL;
if (f == -1) {
decimal_rep = dtoa(value, 0, 0, &decimal_point, &sign, NULL);
f = strlen(decimal_rep) - 1;
} else {
decimal_rep = dtoa(value, 2, f + 1, &decimal_point, &sign, NULL);
}
int decimal_rep_length = strlen(decimal_rep);
ASSERT(decimal_rep_length > 0);
ASSERT(decimal_rep_length <= f + 1);
USE(decimal_rep_length);
int exponent = decimal_point - 1;
char* result =
CreateExponentialRepresentation(decimal_rep, exponent, negative, f+1);
freedtoa(decimal_rep);
return result;
}
char* DoubleToPrecisionCString(double value, int p) {
ASSERT(p >= 1 && p <= 21);
bool negative = false;
if (value < 0) {
value = -value;
negative = true;
}
// Find a sufficiently precise decimal representation of n.
int decimal_point;
int sign;
char* decimal_rep = dtoa(value, 2, p, &decimal_point, &sign, NULL);
int decimal_rep_length = strlen(decimal_rep);
ASSERT(decimal_rep_length <= p);
int exponent = decimal_point - 1;
char* result = NULL;
if (exponent < -6 || exponent >= p) {
result =
CreateExponentialRepresentation(decimal_rep, exponent, negative, p);
} else {
// Use fixed notation.
//
// Leave room in the result for appending a minus, a period and in
// the case where decimal_point is not positive for a zero in
// front of the period.
unsigned result_size = (decimal_point <= 0)
? -decimal_point + p + 3
: p + 2;
StringBuilder builder(result_size + 1);
if (negative) builder.AddCharacter('-');
if (decimal_point <= 0) {
builder.AddString("0.");
builder.AddPadding('0', -decimal_point);
builder.AddString(decimal_rep);
builder.AddPadding('0', p - decimal_rep_length);
} else {
const int m = Min(decimal_rep_length, decimal_point);
builder.AddSubstring(decimal_rep, m);
builder.AddPadding('0', decimal_point - decimal_rep_length);
if (decimal_point < p) {
builder.AddCharacter('.');
const int extra = negative ? 2 : 1;
if (decimal_rep_length > decimal_point) {
const int len = strlen(decimal_rep + decimal_point);
const int n = Min(len, p - (builder.position() - extra));
builder.AddSubstring(decimal_rep + decimal_point, n);
}
builder.AddPadding('0', extra + (p - builder.position()));
}
}
result = builder.Finalize();
}
freedtoa(decimal_rep);
return result;
}
char* DoubleToRadixCString(double value, int radix) {
ASSERT(radix >= 2 && radix <= 36);
// Character array used for conversion.
static const char chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
// Buffer for the integer part of the result. 1024 chars is enough
// for max integer value in radix 2. We need room for a sign too.
static const int kBufferSize = 1100;
char integer_buffer[kBufferSize];
integer_buffer[kBufferSize - 1] = '\0';
// Buffer for the decimal part of the result. We only generate up
// to kBufferSize - 1 chars for the decimal part.
char decimal_buffer[kBufferSize];
decimal_buffer[kBufferSize - 1] = '\0';
// Make sure the value is positive.
bool is_negative = value < 0.0;
if (is_negative) value = -value;
// Get the integer part and the decimal part.
double integer_part = floor(value);
double decimal_part = value - integer_part;
// Convert the integer part starting from the back. Always generate
// at least one digit.
int integer_pos = kBufferSize - 2;
do {
integer_buffer[integer_pos--] =
chars[static_cast<int>(fmod(integer_part, radix))];
integer_part /= radix;
} while (integer_part >= 1.0);
// Sanity check.
ASSERT(integer_pos > 0);
// Add sign if needed.
if (is_negative) integer_buffer[integer_pos--] = '-';
// Convert the decimal part. Repeatedly multiply by the radix to
// generate the next char. Never generate more than kBufferSize - 1
// chars.
//
// TODO(1093998): We will often generate a full decimal_buffer of
// chars because hitting zero will often not happen. The right
// solution would be to continue until the string representation can
// be read back and yield the original value. To implement this
// efficiently, we probably have to modify dtoa.
int decimal_pos = 0;
while ((decimal_part > 0.0) && (decimal_pos < kBufferSize - 1)) {
decimal_part *= radix;
decimal_buffer[decimal_pos++] =
chars[static_cast<int>(floor(decimal_part))];
decimal_part -= floor(decimal_part);
}
decimal_buffer[decimal_pos] = '\0';
// Compute the result size.
int integer_part_size = kBufferSize - 2 - integer_pos;
// Make room for zero termination.
unsigned result_size = integer_part_size + decimal_pos;
// If the number has a decimal part, leave room for the period.
if (decimal_pos > 0) result_size++;
// Allocate result and fill in the parts.
StringBuilder builder(result_size + 1);
builder.AddSubstring(integer_buffer + integer_pos + 1, integer_part_size);
if (decimal_pos > 0) builder.AddCharacter('.');
builder.AddSubstring(decimal_buffer, decimal_pos);
return builder.Finalize();
}
} } // namespace v8::internal

View File

@ -1,116 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#ifndef V8_CONVERSIONS_H_
#define V8_CONVERSIONS_H_
namespace v8 { namespace internal {
// The fast double-to-int conversion routine does not guarantee
// rounding towards zero.
// The result is unspecified if x is infinite or NaN, or if the rounded
// integer value is outside the range of type int.
static inline int FastD2I(double x);
static inline double FastI2D(int x) {
// There is no rounding involved in converting an integer to a
// double, so this code should compile to a few instructions without
// any FPU pipeline stalls.
return static_cast<double>(x);
}
static inline double FastUI2D(unsigned x) {
// There is no rounding involved in converting an unsigned integer to a
// double, so this code should compile to a few instructions without
// any FPU pipeline stalls.
return static_cast<double>(x);
}
// This function should match the exact semantics of ECMA-262 9.4.
static inline double DoubleToInteger(double x);
// This function should match the exact semantics of ECMA-262 9.5.
static inline int32_t DoubleToInt32(double x);
// This function should match the exact semantics of ECMA-262 9.6.
static inline uint32_t DoubleToUint32(double x) {
return static_cast<uint32_t>(DoubleToInt32(x));
}
// Returns the value (0 .. 15) of a hexadecimal character c.
// If c is not a legal hexadecimal character, returns a value < 0.
int HexValue(uc32 c);
// Enumeration for allowing octals and ignoring junk when converting
// strings to numbers.
enum ConversionFlags {
NO_FLAGS = 0,
ALLOW_HEX = 1,
ALLOW_OCTALS = 2,
ALLOW_TRAILING_JUNK = 4
};
// Convert from Number object to C integer.
static inline int32_t NumberToInt32(Object* number);
static inline uint32_t NumberToUint32(Object* number);
// Converts a string into a double value according to ECMA-262 9.3.1
double StringToDouble(const char* str, int flags, double empty_string_val = 0);
double StringToDouble(String* str, int flags, double empty_string_val = 0);
// Converts a string into an integer.
int StringToInt(String* str, int index, int radix, double* value);
int StringToInt(const char* str, int index, int radix, double* value);
// Converts a double to a string value according to ECMA-262 9.8.1.
// The buffer should be large enough for any floating point number.
// 100 characters is enough.
const char* DoubleToCString(double value, Vector<char> buffer);
// Convert an int to a null-terminated string. The returned string is
// located inside the buffer, but not necessarily at the start.
const char* IntToCString(int n, Vector<char> buffer);
// Additional number to string conversions for the number type.
// The caller is responsible for calling free on the returned pointer.
char* DoubleToFixedCString(double value, int f);
char* DoubleToExponentialCString(double value, int f);
char* DoubleToPrecisionCString(double value, int f);
char* DoubleToRadixCString(double value, int radix);
} } // namespace v8::internal
#endif // V8_CONVERSIONS_H_

View File

@ -1,56 +0,0 @@
// Copyright 2007-2008 the V8 project 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.
#include "v8.h"
#include "counters.h"
#include "platform.h"
namespace v8 { namespace internal {
CounterLookupCallback StatsTable::lookup_function_ = NULL;
// Start the timer.
void StatsCounterTimer::Start() {
if (!counter_.Enabled())
return;
stop_time_ = 0;
start_time_ = OS::Ticks();
}
// Stop the timer and record the results.
void StatsCounterTimer::Stop() {
if (!counter_.Enabled())
return;
stop_time_ = OS::Ticks();
// Compute the delta between start and stop, in milliseconds.
int milliseconds = static_cast<int>(stop_time_ - start_time_) / 1000;
counter_.Increment(milliseconds);
}
} } // namespace v8::internal

View File

@ -1,200 +0,0 @@
// Copyright 2007-2008 the V8 project 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.
#ifndef V8_COUNTERS_H_
#define V8_COUNTERS_H_
#include <wchar.h>
namespace v8 { namespace internal {
// StatsCounters is an interface for plugging into external
// counters for monitoring. Counters can be looked up and
// manipulated by name.
class StatsTable : public AllStatic {
public:
// Register an application-defined function where
// counters can be looked up.
static void SetCounterFunction(CounterLookupCallback f) {
lookup_function_ = f;
}
static bool HasCounterFunction() {
return lookup_function_ != NULL;
}
// Lookup the location of a counter by name. If the lookup
// is successful, returns a non-NULL pointer for writing the
// value of the counter. Each thread calling this function
// may receive a different location to store it's counter.
// The return value must not be cached and re-used across
// threads, although a single thread is free to cache it.
static int *FindLocation(const wchar_t* name) {
if (!lookup_function_) return NULL;
return lookup_function_(name);
}
private:
static CounterLookupCallback lookup_function_;
};
// StatsCounters are dynamically created values which can be tracked in
// the StatsTable. They are designed to be lightweight to create and
// easy to use.
//
// Internally, a counter represents a value in a row of a StatsTable.
// The row has a 32bit value for each process/thread in the table and also
// a name (stored in the table metadata). Since the storage location can be
// thread-specific, this class cannot be shared across threads.
//
// This class is designed to be POD initialized. It will be registered with
// the counter system on first use. For example:
// StatsCounter c = { L"c:myctr", NULL, false };
struct StatsCounter {
const wchar_t* name_;
int* ptr_;
bool lookup_done_;
// Sets the counter to a specific value.
void Set(int value) {
int* loc = GetPtr();
if (loc) *loc = value;
}
// Increments the counter.
void Increment() {
int* loc = GetPtr();
if (loc) (*loc)++;
}
void Increment(int value) {
int* loc = GetPtr();
if (loc)
(*loc) += value;
}
// Decrements the counter.
void Decrement() {
int* loc = GetPtr();
if (loc) (*loc)--;
}
void Decrement(int value) {
int* loc = GetPtr();
if (loc) (*loc) -= value;
}
// Is this counter enabled?
// Returns false if table is full.
bool Enabled() {
return GetPtr() != NULL;
}
// Get the internal pointer to the counter. This is used
// by the code generator to emit code that manipulates a
// given counter without calling the runtime system.
int* GetInternalPointer() {
int* loc = GetPtr();
ASSERT(loc != NULL);
return loc;
}
protected:
// Returns the cached address of this counter location.
int* GetPtr() {
if (lookup_done_)
return ptr_;
lookup_done_ = true;
ptr_ = StatsTable::FindLocation(name_);
return ptr_;
}
};
// StatsCounterTimer t = { { L"t:foo", NULL, false }, 0, 0 };
struct StatsCounterTimer {
StatsCounter counter_;
int64_t start_time_;
int64_t stop_time_;
// Start the timer.
void Start();
// Stop the timer and record the results.
void Stop();
// Returns true if the timer is running.
bool Running() {
return counter_.Enabled() && start_time_ != 0 && stop_time_ == 0;
}
};
// A StatsRate is a combination of both a timer and a counter so that
// several statistics can be produced:
// min, max, avg, count, total
//
// For example:
// StatsCounter c = { { { L"t:myrate", NULL, false }, 0, 0 },
// { L"c:myrate", NULL, false } };
struct StatsRate {
StatsCounterTimer timer_;
StatsCounter counter_;
// Starts the rate timer.
void Start() {
timer_.Start();
}
// Stops the rate and records the time.
void Stop() {
if (timer_.Running()) {
timer_.Stop();
counter_.Increment();
}
}
};
// Helper class for scoping a rate.
class StatsRateScope BASE_EMBEDDED {
public:
explicit StatsRateScope(StatsRate* rate) :
rate_(rate) {
rate_->Start();
}
~StatsRateScope() {
rate_->Stop();
}
private:
StatsRate* rate_;
};
} } // namespace v8::internal
#endif // V8_COUNTERS_H_

View File

@ -1,124 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
// CPU specific code for arm independent of OS goes here.
#if defined(__arm__)
#include <sys/syscall.h> // for cache flushing.
#endif
#include "v8.h"
#include "cpu.h"
namespace v8 { namespace internal {
void CPU::Setup() {
// Nothing to do.
}
void CPU::FlushICache(void* start, size_t size) {
#if !defined (__arm__)
// Not generating ARM instructions for C-code. This means that we are
// building an ARM emulator based target. No I$ flushes are necessary.
#else
// Ideally, we would call
// syscall(__ARM_NR_cacheflush, start,
// reinterpret_cast<intptr_t>(start) + size, 0);
// however, syscall(int, ...) is not supported on all platforms, especially
// not when using EABI, so we call the __ARM_NR_cacheflush syscall directly.
register uint32_t beg asm("a1") = reinterpret_cast<uint32_t>(start);
register uint32_t end asm("a2") =
reinterpret_cast<uint32_t>(start) + size;
register uint32_t flg asm("a3") = 0;
#ifdef __ARM_EABI__
register uint32_t scno asm("r7") = __ARM_NR_cacheflush;
#if defined (__arm__) && !defined(__thumb__)
// __arm__ may be defined in thumb mode.
asm volatile(
"swi 0x0"
: "=r" (beg)
: "0" (beg), "r" (end), "r" (flg), "r" (scno));
#else
asm volatile(
"@ Enter ARM Mode \n\t"
"adr r3, 1f \n\t"
"bx r3 \n\t"
".ALIGN 4 \n\t"
".ARM \n"
"1: swi 0x0 \n\t"
"@ Enter THUMB Mode\n\t"
"adr r3, 2f+1 \n\t"
"bx r3 \n\t"
".THUMB \n"
"2: \n\t"
: "=r" (beg)
: "0" (beg), "r" (end), "r" (flg), "r" (scno)
: "r3");
#endif
#else
#if defined (__arm__) && !defined(__thumb__)
// __arm__ may be defined in thumb mode.
asm volatile(
"swi %1"
: "=r" (beg)
: "i" (__ARM_NR_cacheflush), "0" (beg), "r" (end), "r" (flg));
#else
// Do not use the value of __ARM_NR_cacheflush in the inline assembly
// below, because the thumb mode value would be used, which would be
// wrong, since we switch to ARM mode before executing the swi instruction
asm volatile(
"@ Enter ARM Mode \n\t"
"adr r3, 1f \n\t"
"bx r3 \n\t"
".ALIGN 4 \n\t"
".ARM \n"
"1: swi 0x9f0002 \n"
"@ Enter THUMB Mode\n\t"
"adr r3, 2f+1 \n\t"
"bx r3 \n\t"
".THUMB \n"
"2: \n\t"
: "=r" (beg)
: "0" (beg), "r" (end), "r" (flg)
: "r3");
#endif
#endif
#endif
}
void CPU::DebugBreak() {
#if !defined (__arm__)
UNIMPLEMENTED(); // when building ARM emulator target
#else
asm volatile("bkpt 0");
#endif
}
} } // namespace v8::internal

View File

@ -1,64 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
// CPU specific code for ia32 independent of OS goes here.
#include "v8.h"
#include "cpu.h"
namespace v8 { namespace internal {
void CPU::Setup() {
// Nothing to do.
}
void CPU::FlushICache(void* start, size_t size) {
// No need to flush the instruction cache on Intel. On Intel instruction
// cache flushing is only necessary when multiple cores running the same
// code simultaneously. V8 (and JavaScript) is single threaded and when code
// is patched on an intel CPU the core performing the patching will have its
// own instruction cache updated automatically.
// If flushing of the instruction cache becomes necessary Windows have the
// API function FlushInstructionCache.
}
void CPU::DebugBreak() {
#ifdef WIN32
// To avoid Visual Studio runtime support the following code can be used
// instead
// __asm { int 3 }
__debugbreak();
#else
asm("int $3");
#endif
}
} } // namespace v8::internal

View File

@ -1,64 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
// This module contains the architecture-specific code. This make the rest of
// the code less dependent on differences between different processor
// architecture.
// The classes have the same definition for all architectures. The
// implementation for a particular architecture is put in cpu_<arch>.cc.
// The build system then uses the implementation for the target architecture.
//
#ifndef V8_CPU_H_
#define V8_CPU_H_
namespace v8 { namespace internal {
// ----------------------------------------------------------------------------
// CPU
//
// This class has static methods for the architecture specific functions. Add
// methods here to cope with differences between the supported architectures.
//
// For each architecture the file cpu_<arch>.cc contains the implementation of
// these functions.
class CPU : public AllStatic {
public:
// Initializes the cpu architecture support. Called once at VM startup.
static void Setup();
// Flush instruction cache.
static void FlushICache(void* start, size_t size);
// Try to activate a system level debugger.
static void DebugBreak();
};
} } // namespace v8::internal
#endif // V8_CPU_H_

View File

@ -1,120 +0,0 @@
// Copyright 2008 the V8 project 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.
#include <readline/readline.h>
#include <readline/history.h>
#include "d8.h"
namespace v8 {
class ReadLineEditor: public LineEditor {
public:
ReadLineEditor() : LineEditor(LineEditor::READLINE, "readline") { }
virtual i::SmartPointer<char> Prompt(const char* prompt);
virtual bool Open();
virtual bool Close();
virtual void AddHistory(const char* str);
private:
static char** AttemptedCompletion(const char* text, int start, int end);
static char* CompletionGenerator(const char* text, int state);
static char kWordBreakCharacters[];
};
static ReadLineEditor read_line_editor;
char ReadLineEditor::kWordBreakCharacters[] = {' ', '\t', '\n', '"',
'\\', '\'', '`', '@', '.', '>', '<', '=', ';', '|', '&', '{', '(',
'\0'};
bool ReadLineEditor::Open() {
rl_initialize();
rl_attempted_completion_function = AttemptedCompletion;
rl_completer_word_break_characters = kWordBreakCharacters;
rl_bind_key('\t', rl_complete);
using_history();
return read_history(Shell::kHistoryFileName) == 0;
}
bool ReadLineEditor::Close() {
return write_history(Shell::kHistoryFileName) == 0;
}
i::SmartPointer<char> ReadLineEditor::Prompt(const char* prompt) {
char* result = readline(prompt);
return i::SmartPointer<char>(result);
}
void ReadLineEditor::AddHistory(const char* str) {
add_history(str);
}
char** ReadLineEditor::AttemptedCompletion(const char* text,
int start,
int end) {
char** result = rl_completion_matches(text, CompletionGenerator);
rl_attempted_completion_over = true;
return result;
}
char* ReadLineEditor::CompletionGenerator(const char* text, int state) {
static unsigned current_index;
static Persistent<Array> current_completions;
if (state == 0) {
i::SmartPointer<char> full_text(strndup(rl_line_buffer, rl_point));
HandleScope scope;
Handle<Array> completions =
Shell::GetCompletions(String::New(text), String::New(*full_text));
current_completions = Persistent<Array>::New(completions);
current_index = 0;
}
if (current_index < current_completions->Length()) {
HandleScope scope;
Handle<Integer> index = Integer::New(current_index);
Handle<Value> str_obj = current_completions->Get(index);
current_index++;
String::Utf8Value str(str_obj);
return strdup(*str);
} else {
current_completions.Dispose();
current_completions.Clear();
return NULL;
}
}
} // namespace v8

View File

@ -1,348 +0,0 @@
// Copyright 2008 the V8 project 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.
#include "d8.h"
#include "debug.h"
#include "api.h"
#include "natives.h"
namespace v8 {
const char* Shell::kHistoryFileName = ".d8_history";
const char* Shell::kPrompt = "d8> ";
LineEditor *LineEditor::first_ = NULL;
LineEditor::LineEditor(Type type, const char* name)
: type_(type),
name_(name),
next_(first_) {
first_ = this;
}
LineEditor* LineEditor::Get() {
LineEditor* current = first_;
LineEditor* best = current;
while (current != NULL) {
if (current->type_ > best->type_)
best = current;
current = current->next_;
}
return best;
}
class DumbLineEditor: public LineEditor {
public:
DumbLineEditor() : LineEditor(LineEditor::DUMB, "dumb") { }
virtual i::SmartPointer<char> Prompt(const char* prompt);
};
static DumbLineEditor dumb_line_editor;
i::SmartPointer<char> DumbLineEditor::Prompt(const char* prompt) {
static const int kBufferSize = 256;
char buffer[kBufferSize];
printf("%s", prompt);
char* str = fgets(buffer, kBufferSize, stdin);
return i::SmartPointer<char>(str ? i::OS::StrDup(str) : str);
}
Shell::CounterMap Shell::counter_map_;
Persistent<Context> Shell::utility_context_;
Persistent<Context> Shell::evaluation_context_;
// Executes a string within the current v8 context.
bool Shell::ExecuteString(Handle<String> source,
Handle<Value> name,
bool print_result,
bool report_exceptions) {
HandleScope handle_scope;
TryCatch try_catch;
Handle<Script> script = Script::Compile(source, name);
if (script.IsEmpty()) {
// Print errors that happened during compilation.
if (report_exceptions)
ReportException(&try_catch);
return false;
} else {
Handle<Value> result = script->Run();
if (result.IsEmpty()) {
// Print errors that happened during execution.
if (report_exceptions)
ReportException(&try_catch);
return false;
} else {
if (print_result && !result->IsUndefined()) {
// If all went well and the result wasn't undefined then print
// the returned value.
String::Utf8Value str(result);
printf("%s\n", *str);
}
return true;
}
}
}
Handle<Value> Shell::Print(const Arguments& args) {
bool first = true;
for (int i = 0; i < args.Length(); i++) {
HandleScope handle_scope;
if (first) {
first = false;
} else {
printf(" ");
}
String::Utf8Value str(args[i]);
printf("%s", *str);
}
printf("\n");
return Undefined();
}
Handle<Value> Shell::Load(const Arguments& args) {
for (int i = 0; i < args.Length(); i++) {
HandleScope handle_scope;
String::Utf8Value file(args[i]);
Handle<String> source = ReadFile(*file);
if (source.IsEmpty()) {
return ThrowException(String::New("Error loading file"));
}
if (!ExecuteString(source, String::New(*file), false, false)) {
return ThrowException(String::New("Error executing file"));
}
}
return Undefined();
}
Handle<Value> Shell::Quit(const Arguments& args) {
int exit_code = args[0]->Int32Value();
OnExit();
exit(exit_code);
return Undefined();
}
Handle<Value> Shell::Version(const Arguments& args) {
return String::New(V8::GetVersion());
}
void Shell::ReportException(v8::TryCatch* try_catch) {
HandleScope handle_scope;
String::Utf8Value exception(try_catch->Exception());
Handle<Message> message = try_catch->Message();
if (message.IsEmpty()) {
// V8 didn't provide any extra information about this error; just
// print the exception.
printf("%s\n", *exception);
} else {
// Print (filename):(line number): (message).
String::Utf8Value filename(message->GetScriptResourceName());
int linenum = message->GetLineNumber();
printf("%s:%i: %s\n", *filename, linenum, *exception);
// Print line of source code.
String::Utf8Value sourceline(message->GetSourceLine());
printf("%s\n", *sourceline);
// Print wavy underline (GetUnderline is deprecated).
int start = message->GetStartColumn();
for (int i = 0; i < start; i++) {
printf(" ");
}
int end = message->GetEndColumn();
for (int i = start; i < end; i++) {
printf("^");
}
printf("\n");
}
}
Handle<Array> Shell::GetCompletions(Handle<String> text, Handle<String> full) {
HandleScope handle_scope;
Context::Scope context_scope(utility_context_);
Handle<Object> global = utility_context_->Global();
Handle<Value> fun = global->Get(String::New("GetCompletions"));
static const int kArgc = 3;
Handle<Value> argv[kArgc] = { evaluation_context_->Global(), text, full };
Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
return handle_scope.Close(Handle<Array>::Cast(val));
}
int* Shell::LookupCounter(const wchar_t* name) {
CounterMap::iterator item = counter_map_.find(name);
if (item != counter_map_.end()) {
Counter* result = (*item).second;
return result->GetValuePtr();
}
Counter* result = new Counter(name);
counter_map_[name] = result;
return result->GetValuePtr();
}
void Shell::Initialize() {
// Set up counters
if (i::FLAG_dump_counters)
V8::SetCounterFunction(LookupCounter);
// Initialize the global objects
HandleScope scope;
Handle<ObjectTemplate> global_template = ObjectTemplate::New();
global_template->Set(String::New("print"), FunctionTemplate::New(Print));
global_template->Set(String::New("load"), FunctionTemplate::New(Load));
global_template->Set(String::New("quit"), FunctionTemplate::New(Quit));
global_template->Set(String::New("version"), FunctionTemplate::New(Version));
utility_context_ = Context::New(NULL, global_template);
utility_context_->SetSecurityToken(Undefined());
Context::Scope utility_scope(utility_context_);
// Install the debugger object in the utility scope
i::Debug::Load();
i::Debug::debug_context()->set_security_token(i::Heap::undefined_value());
i::JSObject* debug = i::Debug::debug_context()->global();
utility_context_->Global()->Set(String::New("$debug"),
Utils::ToLocal(&debug));
// Run the d8 shell utility script in the utility context
int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
i::Vector<const char> shell_source
= i::NativesCollection<i::D8>::GetScriptSource(source_index);
i::Vector<const char> shell_source_name
= i::NativesCollection<i::D8>::GetScriptName(source_index);
Handle<String> source = String::New(shell_source.start(),
shell_source.length());
Handle<String> name = String::New(shell_source_name.start(),
shell_source_name.length());
Script::Compile(source, name)->Run();
// Create the evaluation context
evaluation_context_ = Context::New(NULL, global_template);
evaluation_context_->SetSecurityToken(Undefined());
}
void Shell::OnExit() {
if (i::FLAG_dump_counters) {
::printf("+----------------------------------------+----------+\n");
::printf("| Name | Value |\n");
::printf("+----------------------------------------+----------+\n");
for (CounterMap::iterator i = counter_map_.begin();
i != counter_map_.end();
i++) {
Counter* counter = (*i).second;
::printf("| %-38ls | %8i |\n", counter->name(), counter->value());
}
::printf("+----------------------------------------+----------+\n");
}
}
// Reads a file into a v8 string.
Handle<String> Shell::ReadFile(const char* name) {
FILE* file = i::OS::FOpen(name, "rb");
if (file == NULL) return Handle<String>();
fseek(file, 0, SEEK_END);
int size = ftell(file);
rewind(file);
char* chars = new char[size + 1];
chars[size] = '\0';
for (int i = 0; i < size;) {
int read = fread(&chars[i], 1, size - i, file);
i += read;
}
fclose(file);
Handle<String> result = String::New(chars, size);
delete[] chars;
return result;
}
void Shell::RunShell() {
LineEditor* editor = LineEditor::Get();
printf("V8 version %s [console: %s]\n", V8::GetVersion(), editor->name());
editor->Open();
while (true) {
HandleScope handle_scope;
i::SmartPointer<char> input = editor->Prompt(Shell::kPrompt);
if (input.is_empty())
break;
editor->AddHistory(*input);
Handle<String> name = String::New("(d8)");
ExecuteString(String::New(*input), name, true, true);
}
editor->Close();
printf("\n");
}
int Shell::Main(int argc, char* argv[]) {
i::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
Initialize();
bool run_shell = (argc == 1);
Context::Scope context_scope(evaluation_context_);
for (int i = 1; i < argc; i++) {
char* str = argv[i];
HandleScope handle_scope;
Handle<String> file_name = v8::String::New(str);
Handle<String> source = ReadFile(str);
if (source.IsEmpty()) {
printf("Error reading '%s'\n", str);
return 1;
}
if (!ExecuteString(source, file_name, false, true))
return 1;
}
if (run_shell)
RunShell();
OnExit();
return 0;
}
} // namespace v8
int main(int argc, char* argv[]) {
return v8::Shell::Main(argc, argv);
}

View File

@ -1,113 +0,0 @@
// Copyright 2008 the V8 project 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.
#ifndef V8_D8_H_
#define V8_D8_H_
// Disable exceptions on windows to not generate warnings from <map>.
#define _HAS_EXCEPTIONS 0
#include <map>
#include "v8.h"
namespace v8 {
namespace i = v8::internal;
class Counter {
public:
explicit Counter(const wchar_t* name)
: name_(name), value_(0) { }
int* GetValuePtr() { return &value_; }
const wchar_t* name() { return name_; }
int value() { return value_; }
private:
const wchar_t* name_;
int value_;
};
class Shell: public i::AllStatic {
public:
static bool ExecuteString(Handle<String> source,
Handle<Value> name,
bool print_result,
bool report_exceptions);
static void ReportException(TryCatch* try_catch);
static void Initialize();
static void OnExit();
static int* LookupCounter(const wchar_t* name);
static Handle<String> ReadFile(const char* name);
static void RunShell();
static int Main(int argc, char* argv[]);
static Handle<Array> GetCompletions(Handle<String> text,
Handle<String> full);
static Handle<Value> Print(const Arguments& args);
static Handle<Value> Quit(const Arguments& args);
static Handle<Value> Version(const Arguments& args);
static Handle<Value> Load(const Arguments& args);
static const char* kHistoryFileName;
static const char* kPrompt;
private:
static Persistent<Context> utility_context_;
static Persistent<Context> evaluation_context_;
typedef std::map<const wchar_t*, Counter*> CounterMap;
static CounterMap counter_map_;
};
class LineEditor {
public:
enum Type { DUMB = 0, READLINE = 1 };
LineEditor(Type type, const char* name);
virtual ~LineEditor() { }
virtual i::SmartPointer<char> Prompt(const char* prompt) = 0;
virtual bool Open() { return true; }
virtual bool Close() { return true; }
virtual void AddHistory(const char* str) { }
const char* name() { return name_; }
static LineEditor* Get();
private:
Type type_;
const char* name_;
LineEditor* next_;
static LineEditor* first_;
};
} // namespace v8
#endif // V8_D8_H_

View File

@ -1,70 +0,0 @@
// Copyright 2008 the V8 project 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.
// How crappy is it that I have to implement completely basic stuff
// like this myself? Answer: very.
String.prototype.startsWith = function (str) {
if (str.length > this.length)
return false;
return this.substr(0, str.length) == str;
};
function ToInspectableObject(obj) {
if (!obj && typeof obj === 'object') {
return void 0;
} else {
return Object(obj);
}
}
function GetCompletions(global, last, full) {
var full_tokens = full.split();
full = full_tokens.pop();
var parts = full.split('.');
parts.pop();
var current = global;
for (var i = 0; i < parts.length; i++) {
var part = parts[i];
var next = current[part];
if (!next)
return [];
current = next;
}
var result = [];
current = ToInspectableObject(current);
while (typeof current !== 'undefined') {
var mirror = new $debug.ObjectMirror(current);
var properties = mirror.properties();
for (var i = 0; i < properties.length; i++) {
var name = properties[i].name();
if (typeof name === 'string' && name.startsWith(last))
result.push(name);
}
current = ToInspectableObject(current.__proto__);
}
return result;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,265 +0,0 @@
// Copyright 2008 the V8 project 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.
#include "v8.h"
#include "dateparser.h"
namespace v8 { namespace internal {
bool DateParser::Parse(String* str, FixedArray* out) {
ASSERT(out->length() == OUTPUT_SIZE);
InputReader in(str);
TimeZoneComposer tz;
TimeComposer time;
DayComposer day;
while (!in.IsEnd()) {
if (in.IsAsciiDigit()) {
// Parse a number (possibly with 1 or 2 trailing colons).
int n = in.ReadUnsignedNumber();
if (in.Skip(':')) {
if (in.Skip(':')) {
// n + "::"
if (!time.IsEmpty()) return false;
time.Add(n);
time.Add(0);
} else {
// n + ":"
if (!time.Add(n)) return false;
}
} else if (tz.IsExpecting(n)) {
tz.SetAbsoluteMinute(n);
} else if (time.IsExpecting(n)) {
time.AddFinal(n);
// Require end or white space immediately after finalizing time.
if (!in.IsEnd() && !in.SkipWhiteSpace()) return false;
} else {
if (!day.Add(n)) return false;
in.Skip('-'); // Ignore suffix '-' for year, month, or day.
}
} else if (in.IsAsciiAlphaOrAbove()) {
// Parse a "word" (sequence of chars. >= 'A').
uint32_t pre[KeywordTable::kPrefixLength];
int len = in.ReadWord(pre, KeywordTable::kPrefixLength);
int index = KeywordTable::Lookup(pre, len);
KeywordType type = KeywordTable::GetType(index);
if (type == AM_PM && !time.IsEmpty()) {
time.SetHourOffset(KeywordTable::GetValue(index));
} else if (type == MONTH_NAME) {
day.SetNamedMonth(KeywordTable::GetValue(index));
in.Skip('-'); // Ignore suffix '-' for month names
} else if (type == TIME_ZONE_NAME && in.HasReadNumber()) {
tz.Set(KeywordTable::GetValue(index));
} else {
// Garbage words are illegal if no number read yet.
if (in.HasReadNumber()) return false;
}
} else if (in.IsAsciiSign() && (tz.IsUTC() || !time.IsEmpty())) {
// Parse UTC offset (only after UTC or time).
tz.SetSign(in.GetAsciiSignValue());
in.Next();
int n = in.ReadUnsignedNumber();
if (in.Skip(':')) {
tz.SetAbsoluteHour(n);
tz.SetAbsoluteMinute(kNone);
} else {
tz.SetAbsoluteHour(n / 100);
tz.SetAbsoluteMinute(n % 100);
}
} else if (in.Is('(')) {
// Ignore anything from '(' to a matching ')' or end of string.
in.SkipParentheses();
} else if ((in.IsAsciiSign() || in.Is(')')) && in.HasReadNumber()) {
// Extra sign or ')' is illegal if no number read yet.
return false;
} else {
// Ignore other characters.
in.Next();
}
}
return day.Write(out) && time.Write(out) && tz.Write(out);
}
bool DateParser::DayComposer::Write(FixedArray* output) {
int year = 0; // Default year is 0 (=> 2000) for KJS compatibility.
int month = kNone;
int day = kNone;
if (named_month_ == kNone) {
if (index_ < 2) return false;
if (index_ == 3 && !IsDay(comp_[0])) {
// YMD
year = comp_[0];
month = comp_[1];
day = comp_[2];
} else {
// MD(Y)
month = comp_[0];
day = comp_[1];
if (index_ == 3) year = comp_[2];
}
} else {
month = named_month_;
if (index_ < 1) return false;
if (index_ == 1) {
// MD or DM
day = comp_[0];
} else if (!IsDay(comp_[0])) {
// YMD, MYD, or YDM
year = comp_[0];
day = comp_[1];
} else {
// DMY, MDY, or DYM
day = comp_[0];
year = comp_[1];
}
}
if (Between(year, 0, 49)) year += 2000;
else if (Between(year, 50, 99)) year += 1900;
if (!Smi::IsValid(year) || !IsMonth(month) || !IsDay(day)) return false;
output->set(YEAR,
Smi::FromInt(year),
SKIP_WRITE_BARRIER);
output->set(MONTH,
Smi::FromInt(month - 1),
SKIP_WRITE_BARRIER); // 0-based
output->set(DAY,
Smi::FromInt(day),
SKIP_WRITE_BARRIER);
return true;
}
bool DateParser::TimeComposer::Write(FixedArray* output) {
// All time slots default to 0
while (index_ < kSize) {
comp_[index_++] = 0;
}
int& hour = comp_[0];
int& minute = comp_[1];
int& second = comp_[2];
if (hour_offset_ != kNone) {
if (!IsHour12(hour)) return false;
hour %= 12;
hour += hour_offset_;
}
if (!IsHour(hour) || !IsMinute(minute) || !IsSecond(second)) return false;
output->set(HOUR,
Smi::FromInt(hour),
SKIP_WRITE_BARRIER);
output->set(MINUTE,
Smi::FromInt(minute),
SKIP_WRITE_BARRIER);
output->set(SECOND,
Smi::FromInt(second),
SKIP_WRITE_BARRIER);
return true;
}
bool DateParser::TimeZoneComposer::Write(FixedArray* output) {
if (sign_ != kNone) {
if (hour_ == kNone) hour_ = 0;
if (minute_ == kNone) minute_ = 0;
int total_seconds = sign_ * (hour_ * 3600 + minute_ * 60);
if (!Smi::IsValid(total_seconds)) return false;
output->set(UTC_OFFSET,
Smi::FromInt(total_seconds),
SKIP_WRITE_BARRIER);
} else {
output->set(UTC_OFFSET,
Heap::null_value(),
SKIP_WRITE_BARRIER);
}
return true;
}
const int8_t
DateParser::KeywordTable::array[][DateParser::KeywordTable::kEntrySize] = {
{'j', 'a', 'n', DateParser::MONTH_NAME, 1},
{'f', 'e', 'b', DateParser::MONTH_NAME, 2},
{'m', 'a', 'r', DateParser::MONTH_NAME, 3},
{'a', 'p', 'r', DateParser::MONTH_NAME, 4},
{'m', 'a', 'y', DateParser::MONTH_NAME, 5},
{'j', 'u', 'n', DateParser::MONTH_NAME, 6},
{'j', 'u', 'l', DateParser::MONTH_NAME, 7},
{'a', 'u', 'g', DateParser::MONTH_NAME, 8},
{'s', 'e', 'p', DateParser::MONTH_NAME, 9},
{'o', 'c', 't', DateParser::MONTH_NAME, 10},
{'n', 'o', 'v', DateParser::MONTH_NAME, 11},
{'d', 'e', 'c', DateParser::MONTH_NAME, 12},
{'a', 'm', '\0', DateParser::AM_PM, 0},
{'p', 'm', '\0', DateParser::AM_PM, 12},
{'u', 't', '\0', DateParser::TIME_ZONE_NAME, 0},
{'u', 't', 'c', DateParser::TIME_ZONE_NAME, 0},
{'g', 'm', 't', DateParser::TIME_ZONE_NAME, 0},
{'c', 'd', 't', DateParser::TIME_ZONE_NAME, -5},
{'c', 's', 't', DateParser::TIME_ZONE_NAME, -6},
{'e', 'd', 't', DateParser::TIME_ZONE_NAME, -4},
{'e', 's', 't', DateParser::TIME_ZONE_NAME, -5},
{'m', 'd', 't', DateParser::TIME_ZONE_NAME, -6},
{'m', 's', 't', DateParser::TIME_ZONE_NAME, -7},
{'p', 'd', 't', DateParser::TIME_ZONE_NAME, -7},
{'p', 's', 't', DateParser::TIME_ZONE_NAME, -8},
{'\0', '\0', '\0', DateParser::INVALID, 0},
};
// We could use perfect hashing here, but this is not a bottleneck.
int DateParser::KeywordTable::Lookup(const uint32_t* pre, int len) {
int i;
for (i = 0; array[i][kTypeOffset] != INVALID; i++) {
int j = 0;
while (j < kPrefixLength &&
pre[j] == static_cast<uint32_t>(array[i][j])) {
j++;
}
// Check if we have a match and the length is legal.
// Word longer than keyword is only allowed for month names.
if (j == kPrefixLength &&
(len <= kPrefixLength || array[i][kTypeOffset] == MONTH_NAME)) {
return i;
}
}
return i;
}
} } // namespace v8::internal

View File

@ -1,230 +0,0 @@
// Copyright 2008 the V8 project 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.
#ifndef V8_DATEPARSER_H_
#define V8_DATEPARSER_H_
#include "scanner.h"
namespace v8 { namespace internal {
class DateParser : public AllStatic {
public:
// Parse the string as a date. If parsing succeeds, return true after
// filling out the output array as follows (all integers are Smis):
// [0]: year
// [1]: month (0 = Jan, 1 = Feb, ...)
// [2]: day
// [3]: hour
// [4]: minute
// [5]: second
// [6]: UTC offset in seconds, or null value if no timezone specified
// If parsing fails, return false (content of output array is not defined).
static bool Parse(String* str, FixedArray* output);
enum {YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, UTC_OFFSET, OUTPUT_SIZE};
private:
// Range testing
static bool Between(int x, int lo, int hi) { return x >= lo && x <= hi; }
// Indicates a missing value.
static const int kNone = kMaxInt;
// InputReader provides basic string parsing and character classification.
class InputReader BASE_EMBEDDED {
public:
explicit InputReader(String* s) : buffer_(s), has_read_number_(false) {
Next();
}
// Advance to the next character of the string.
void Next() { ch_ = buffer_.has_more() ? buffer_.GetNext() : 0; }
// Read a string of digits as an unsigned number (cap just below kMaxInt).
int ReadUnsignedNumber() {
has_read_number_ = true;
int n;
for (n = 0; IsAsciiDigit() && n < kMaxInt / 10 - 1; Next()) {
n = n * 10 + ch_ - '0';
}
return n;
}
// Read a word (sequence of chars. >= 'A'), fill the given buffer with a
// lower-case prefix, and pad any remainder of the buffer with zeroes.
// Return word length.
int ReadWord(uint32_t* prefix, int prefix_size) {
int len;
for (len = 0; IsAsciiAlphaOrAbove(); Next(), len++) {
if (len < prefix_size) prefix[len] = GetAsciiAlphaLower();
}
for (int i = len; i < prefix_size; i++) prefix[i] = 0;
return len;
}
// The skip methods return whether they actually skipped something.
bool Skip(uint32_t c) { return ch_ == c ? (Next(), true) : false; }
bool SkipWhiteSpace() {
return Scanner::kIsWhiteSpace.get(ch_) ? (Next(), true) : false;
}
bool SkipParentheses() {
if (ch_ != '(') return false;
int balance = 0;
do {
if (ch_ == ')') --balance;
else if (ch_ == '(') ++balance;
Next();
} while (balance > 0 && ch_);
return true;
}
// Character testing/classification. Non-ASCII digits are not supported.
bool Is(uint32_t c) const { return ch_ == c; }
bool IsEnd() const { return ch_ == 0; }
bool IsAsciiDigit() const { return IsDecimalDigit(ch_); }
bool IsAsciiAlphaOrAbove() const { return ch_ >= 'A'; }
bool IsAsciiSign() const { return ch_ == '+' || ch_ == '-'; }
// Return 1 for '+' and -1 for '-'.
int GetAsciiSignValue() const { return 44 - static_cast<int>(ch_); }
// Indicates whether any (possibly empty!) numbers have been read.
bool HasReadNumber() const { return has_read_number_; }
private:
// If current character is in 'A'-'Z' or 'a'-'z', return its lower-case.
// Else, return something outside of 'A'-'Z' and 'a'-'z'.
uint32_t GetAsciiAlphaLower() const { return ch_ | 32; }
StringInputBuffer buffer_;
bool has_read_number_;
uint32_t ch_;
};
enum KeywordType { INVALID, MONTH_NAME, TIME_ZONE_NAME, AM_PM };
// KeywordTable maps names of months, time zones, am/pm to numbers.
class KeywordTable : public AllStatic {
public:
// Look up a word in the keyword table and return an index.
// 'pre' contains a prefix of the word, zero-padded to size kPrefixLength
// and 'len' is the word length.
static int Lookup(const uint32_t* pre, int len);
// Get the type of the keyword at index i.
static KeywordType GetType(int i) {
return static_cast<KeywordType>(array[i][kTypeOffset]);
}
// Get the value of the keyword at index i.
static int GetValue(int i) { return array[i][kValueOffset]; }
static const int kPrefixLength = 3;
static const int kTypeOffset = kPrefixLength;
static const int kValueOffset = kTypeOffset + 1;
static const int kEntrySize = kValueOffset + 1;
static const int8_t array[][kEntrySize];
};
class TimeZoneComposer BASE_EMBEDDED {
public:
TimeZoneComposer() : sign_(kNone), hour_(kNone), minute_(kNone) {}
void Set(int offset_in_hours) {
sign_ = offset_in_hours < 0 ? -1 : 1;
hour_ = offset_in_hours * sign_;
minute_ = 0;
}
void SetSign(int sign) { sign_ = sign < 0 ? -1 : 1; }
void SetAbsoluteHour(int hour) { hour_ = hour; }
void SetAbsoluteMinute(int minute) { minute_ = minute; }
bool IsExpecting(int n) const {
return hour_ != kNone && minute_ == kNone && TimeComposer::IsMinute(n);
}
bool IsUTC() const { return hour_ == 0 && minute_ == 0; }
bool Write(FixedArray* output);
private:
int sign_;
int hour_;
int minute_;
};
class TimeComposer BASE_EMBEDDED {
public:
TimeComposer() : index_(0), hour_offset_(kNone) {}
bool IsEmpty() const { return index_ == 0; }
bool IsExpecting(int n) const {
return (index_ == 1 && IsMinute(n)) || (index_ == 2 && IsSecond(n));
}
bool Add(int n) {
return index_ < kSize ? (comp_[index_++] = n, true) : false;
}
bool AddFinal(int n) {
if (!Add(n)) return false;
while (index_ < kSize) comp_[index_++] = 0;
return true;
}
void SetHourOffset(int n) { hour_offset_ = n; }
bool Write(FixedArray* output);
static bool IsMinute(int x) { return Between(x, 0, 59); }
private:
static bool IsHour(int x) { return Between(x, 0, 23); }
static bool IsHour12(int x) { return Between(x, 0, 12); }
static bool IsSecond(int x) { return Between(x, 0, 59); }
static const int kSize = 3;
int comp_[kSize];
int index_;
int hour_offset_;
};
class DayComposer BASE_EMBEDDED {
public:
DayComposer() : index_(0), named_month_(kNone) {}
bool IsEmpty() const { return index_ == 0; }
bool Add(int n) {
return index_ < kSize ? (comp_[index_++] = n, true) : false;
}
void SetNamedMonth(int n) { named_month_ = n; }
bool Write(FixedArray* output);
private:
static bool IsMonth(int x) { return Between(x, 1, 12); }
static bool IsDay(int x) { return Between(x, 1, 31); }
static const int kSize = 3;
int comp_[kSize];
int index_;
int named_month_;
};
};
} } // namespace v8::internal
#endif // V8_DATEPARSER_H_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,582 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#ifndef V8_V8_DEBUG_H_
#define V8_V8_DEBUG_H_
#include "../include/v8-debug.h"
#include "assembler.h"
#include "code-stubs.h"
#include "execution.h"
#include "factory.h"
#include "platform.h"
#include "string-stream.h"
namespace v8 { namespace internal {
// Step actions. NOTE: These values are in macros.py as well.
enum StepAction {
StepNone = -1, // Stepping not prepared.
StepOut = 0, // Step out of the current function.
StepNext = 1, // Step to the next statement in the current function.
StepIn = 2, // Step into new functions invoked or the next statement
// in the current function.
StepMin = 3, // Perform a minimum step in the current function.
StepInMin = 4 // Step into new functions invoked or perform a minimum step
// in the current function.
};
// Type of exception break. NOTE: These values are in macros.py as well.
enum ExceptionBreakType {
BreakException = 0,
BreakUncaughtException = 1
};
// Type of exception break. NOTE: These values are in macros.py as well.
enum BreakLocatorType {
ALL_BREAK_LOCATIONS = 0,
SOURCE_BREAK_LOCATIONS = 1
};
// Class for iterating through the break points in a function and changing
// them.
class BreakLocationIterator {
public:
explicit BreakLocationIterator(Handle<DebugInfo> debug_info,
BreakLocatorType type);
virtual ~BreakLocationIterator();
void Next();
void Next(int count);
void FindBreakLocationFromAddress(Address pc);
void FindBreakLocationFromPosition(int position);
void Reset();
bool Done() const;
void SetBreakPoint(Handle<Object> break_point_object);
void ClearBreakPoint(Handle<Object> break_point_object);
void SetOneShot();
void ClearOneShot();
void PrepareStepIn();
bool IsExit() const;
bool HasBreakPoint();
bool IsDebugBreak();
Object* BreakPointObjects();
inline int code_position() { return pc() - debug_info_->code()->entry(); }
inline int break_point() { return break_point_; }
inline int position() { return position_; }
inline int statement_position() { return statement_position_; }
inline Address pc() { return reloc_iterator_->rinfo()->pc(); }
inline Code* code() { return debug_info_->code(); }
inline RelocInfo* rinfo() { return reloc_iterator_->rinfo(); }
inline RelocInfo::Mode rmode() const {
return reloc_iterator_->rinfo()->rmode();
}
inline RelocInfo* original_rinfo() {
return reloc_iterator_original_->rinfo();
}
inline RelocInfo::Mode original_rmode() const {
return reloc_iterator_original_->rinfo()->rmode();
}
protected:
bool RinfoDone() const;
void RinfoNext();
BreakLocatorType type_;
int break_point_;
int position_;
int statement_position_;
Handle<DebugInfo> debug_info_;
RelocIterator* reloc_iterator_;
RelocIterator* reloc_iterator_original_;
private:
void SetDebugBreak();
void ClearDebugBreak();
DISALLOW_COPY_AND_ASSIGN(BreakLocationIterator);
};
// Linked list holding debug info objects. The debug info objects are kept as
// weak handles to avoid a debug info object to keep a function alive.
class DebugInfoListNode {
public:
explicit DebugInfoListNode(DebugInfo* debug_info);
virtual ~DebugInfoListNode();
DebugInfoListNode* next() { return next_; }
void set_next(DebugInfoListNode* next) { next_ = next; }
Handle<DebugInfo> debug_info() { return debug_info_; }
private:
// Global (weak) handle to the debug info object.
Handle<DebugInfo> debug_info_;
// Next pointer for linked list.
DebugInfoListNode* next_;
};
// This class contains the debugger support. The main purpose is to handle
// setting break points in the code.
//
// This class controls the debug info for all functions which currently have
// active breakpoints in them. This debug info is held in the heap root object
// debug_info which is a FixedArray. Each entry in this list is of class
// DebugInfo.
class Debug {
public:
static void Setup(bool create_heap_objects);
static bool Load();
static void Unload();
static bool IsLoaded() { return !debug_context_.is_null(); }
static bool InDebugger() { return Top::is_break(); }
static void Iterate(ObjectVisitor* v);
static Object* Break(Arguments args);
static void SetBreakPoint(Handle<SharedFunctionInfo> shared,
int source_position,
Handle<Object> break_point_object);
static void ClearBreakPoint(Handle<Object> break_point_object);
static void FloodWithOneShot(Handle<SharedFunctionInfo> shared);
static void FloodHandlerWithOneShot();
static void ChangeBreakOnException(ExceptionBreakType type, bool enable);
static void PrepareStep(StepAction step_action, int step_count);
static void ClearStepping();
static bool StepNextContinue(BreakLocationIterator* break_location_iterator,
JavaScriptFrame* frame);
static Handle<DebugInfo> GetDebugInfo(Handle<SharedFunctionInfo> shared);
static bool HasDebugInfo(Handle<SharedFunctionInfo> shared);
// Returns whether the operation succedded.
static bool EnsureDebugInfo(Handle<SharedFunctionInfo> shared);
static bool IsDebugBreak(Address addr);
// Check whether a code stub with the specified major key is a possible break
// point location.
static bool IsSourceBreakStub(Code* code);
static bool IsBreakStub(Code* code);
// Find the builtin to use for invoking the debug break
static Handle<Code> FindDebugBreak(RelocInfo* rinfo);
static Handle<Object> GetSourceBreakLocations(
Handle<SharedFunctionInfo> shared);
static Code* GetCodeTarget(Address target);
// Getter for the debug_context.
inline static Handle<Context> debug_context() { return debug_context_; }
// Check whether a global object is the debug global object.
static bool IsDebugGlobal(GlobalObject* global);
// Fast check to see if any break points are active.
inline static bool has_break_points() { return has_break_points_; }
static bool StepInActive() { return thread_local_.step_into_fp_ != 0; }
static Address step_in_fp() { return thread_local_.step_into_fp_; }
static Address* step_in_fp_addr() { return &thread_local_.step_into_fp_; }
// Getter and setter for the disable break state.
static bool disable_break() { return disable_break_; }
static void set_disable_break(bool disable_break) {
disable_break_ = disable_break;
}
// Getters for the current exception break state.
static bool break_on_exception() { return break_on_exception_; }
static bool break_on_uncaught_exception() {
return break_on_uncaught_exception_;
}
enum AddressId {
k_after_break_target_address,
k_debug_break_return_address,
k_register_address
};
// Support for setting the address to jump to when returning from break point.
static Address* after_break_target_address() {
return reinterpret_cast<Address*>(&thread_local_.after_break_target_);
}
// Support for saving/restoring registers when handling debug break calls.
static Object** register_address(int r) {
return &registers_[r];
}
// Address of the debug break return entry code.
static Code* debug_break_return_entry() { return debug_break_return_entry_; }
// Support for getting the address of the debug break on return code.
static Code** debug_break_return_address() {
return &debug_break_return_;
}
static const int kEstimatedNofDebugInfoEntries = 16;
static const int kEstimatedNofBreakPointsInFunction = 16;
static void HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data);
friend class Debugger;
friend Handle<FixedArray> GetDebuggedFunctions(); // Found in test-debug.cc
// Threading support.
static char* ArchiveDebug(char* to);
static char* RestoreDebug(char* from);
static int ArchiveSpacePerThread();
// Code generation assumptions.
static const int kIa32CallInstructionLength = 5;
static const int kIa32JSReturnSequenceLength = 6;
private:
static bool CompileDebuggerScript(int index);
static void ClearOneShot();
static void ActivateStepIn(StackFrame* frame);
static void ClearStepIn();
static void ClearStepNext();
// Returns whether the compile succedded.
static bool EnsureCompiled(Handle<SharedFunctionInfo> shared);
static void RemoveDebugInfo(Handle<DebugInfo> debug_info);
static void SetAfterBreakTarget(JavaScriptFrame* frame);
static Handle<Object> CheckBreakPoints(Handle<Object> break_point);
static bool CheckBreakPoint(Handle<Object> break_point_object);
// Global handle to debug context where all the debugger JavaScript code is
// loaded.
static Handle<Context> debug_context_;
// Boolean state indicating whether any break points are set.
static bool has_break_points_;
static DebugInfoListNode* debug_info_list_;
static bool disable_break_;
static bool break_on_exception_;
static bool break_on_uncaught_exception_;
// Per-thread:
class ThreadLocal {
public:
// Step action for last step performed.
StepAction last_step_action_;
// Source statement position from last step next action.
int last_statement_position_;
// Number of steps left to perform before debug event.
int step_count_;
// Frame pointer from last step next action.
Address last_fp_;
// Frame pointer for frame from which step in was performed.
Address step_into_fp_;
// Storage location for jump when exiting debug break calls.
Address after_break_target_;
};
// Storage location for registers when handling debug break calls
static JSCallerSavedBuffer registers_;
static ThreadLocal thread_local_;
static void ThreadInit();
// Code object for debug break return entry code.
static Code* debug_break_return_entry_;
// Code to call for handling debug break on return.
static Code* debug_break_return_;
DISALLOW_COPY_AND_ASSIGN(Debug);
};
class DebugMessageThread;
class Debugger {
public:
static void DebugRequest(const uint16_t* json_request, int length);
static Handle<Object> MakeJSObject(Vector<const char> constructor_name,
int argc, Object*** argv,
bool* caught_exception);
static Handle<Object> MakeExecutionState(bool* caught_exception);
static Handle<Object> MakeBreakEvent(Handle<Object> exec_state,
Handle<Object> break_points_hit,
bool* caught_exception);
static Handle<Object> MakeExceptionEvent(Handle<Object> exec_state,
Handle<Object> exception,
bool uncaught,
bool* caught_exception);
static Handle<Object> MakeNewFunctionEvent(Handle<Object> func,
bool* caught_exception);
static Handle<Object> MakeCompileEvent(Handle<Script> script,
Handle<Object> script_function,
bool* caught_exception);
static Handle<String> ProcessRequest(Handle<Object> exec_state,
Handle<Object> request,
bool stopped);
static void OnDebugBreak(Handle<Object> break_points_hit);
static void OnException(Handle<Object> exception, bool uncaught);
static void OnBeforeCompile(Handle<Script> script);
static void OnAfterCompile(Handle<Script> script,
Handle<JSFunction> fun);
static void OnNewFunction(Handle<JSFunction> fun);
static void ProcessDebugEvent(v8::DebugEvent event,
Handle<Object> event_data);
static void SetMessageHandler(v8::DebugMessageHandler handler, void* data);
static void SendMessage(Vector<uint16_t> message);
static void ProcessCommand(Vector<const uint16_t> command);
static void UpdateActiveDebugger();
inline static bool EventActive(v8::DebugEvent event) {
// Currently argument event is not used.
return !Debugger::compiling_natives_ && Debugger::debugger_active_;
}
static void set_debugger_active(bool debugger_active) {
Debugger::debugger_active_ = debugger_active;
}
static bool debugger_active() { return Debugger::debugger_active_; }
static void set_compiling_natives(bool compiling_natives) {
Debugger::compiling_natives_ = compiling_natives;
}
static bool compiling_natives() { return Debugger::compiling_natives_; }
static void set_loading_debugger(bool v) { is_loading_debugger_ = v; }
static bool is_loading_debugger() { return Debugger::is_loading_debugger_; }
private:
static bool debugger_active_; // Are there any active debugger?
static bool compiling_natives_; // Are we compiling natives?
static bool is_loading_debugger_; // Are we loading the debugger?
static DebugMessageThread* message_thread_;
static v8::DebugMessageHandler debug_message_handler_;
static void* debug_message_handler_data_;
};
// A Queue of Vector<uint16_t> objects. A thread-safe version is
// LockingMessageQueue, based on this class.
class MessageQueue BASE_EMBEDDED {
public:
explicit MessageQueue(int size);
~MessageQueue();
bool IsEmpty() const { return start_ == end_; }
Vector<uint16_t> Get();
void Put(const Vector<uint16_t>& message);
void Clear() { start_ = end_ = 0; } // Queue is empty after Clear().
private:
// Doubles the size of the message queue, and copies the messages.
void Expand();
Vector<uint16_t>* messages_;
int start_;
int end_;
int size_; // The size of the queue buffer. Queue can hold size-1 messages.
};
// LockingMessageQueue is a thread-safe circular buffer of Vector<uint16_t>
// messages. The message data is not managed by LockingMessageQueue.
// Pointers to the data are passed in and out. Implemented by adding a
// Mutex to MessageQueue. Includes logging of all puts and gets.
class LockingMessageQueue BASE_EMBEDDED {
public:
explicit LockingMessageQueue(int size);
~LockingMessageQueue();
bool IsEmpty() const;
Vector<uint16_t> Get();
void Put(const Vector<uint16_t>& message);
void Clear();
private:
MessageQueue queue_;
Mutex* lock_;
DISALLOW_COPY_AND_ASSIGN(LockingMessageQueue);
};
/* This class is the data for a running thread that serializes
* event messages and command processing for the debugger.
* All uncommented methods are called only from this message thread.
*/
class DebugMessageThread: public Thread {
public:
DebugMessageThread(); // Called from API thread.
virtual ~DebugMessageThread(); // Never called.
// Called by V8 thread. Reports events from V8 VM.
// Also handles command processing in stopped state of V8,
// when host_running_ is false.
void DebugEvent(v8::DebugEvent,
Handle<Object> exec_state,
Handle<Object> event_data);
// Puts event on the output queue. Called by V8.
// This is where V8 hands off
// processing of the event to the DebugMessageThread thread,
// which forwards it to the debug_message_handler set by the API.
void SendMessage(Vector<uint16_t> event_json);
// Formats an event into JSON, and calls SendMessage.
void SetEventJSONFromEvent(Handle<Object> event_data);
// Puts a command coming from the public API on the queue. Called
// by the API client thread. This is where the API client hands off
// processing of the command to the DebugMessageThread thread.
void ProcessCommand(Vector<uint16_t> command);
void OnDebuggerInactive();
// Main function of DebugMessageThread thread.
void Run();
bool host_running_; // Is the debugging host running or stopped?
Semaphore* command_received_; // Non-zero when command queue is non-empty.
Semaphore* message_received_; // Exactly equal to message queue length.
private:
bool TwoByteEqualsAscii(Vector<uint16_t> two_byte, const char* ascii);
static const int kQueueInitialSize = 4;
LockingMessageQueue command_queue_;
LockingMessageQueue message_queue_;
DISALLOW_COPY_AND_ASSIGN(DebugMessageThread);
};
// This class is used for entering the debugger. Create an instance in the stack
// to enter the debugger. This will set the current break state, make sure the
// debugger is loaded and switch to the debugger context. If the debugger for
// some reason could not be entered FailedToEnter will return true.
class EnterDebugger BASE_EMBEDDED {
public:
EnterDebugger() : set_(!it_.done()) {
// If there is no JavaScript frames on the stack don't switch to new break
// and break frame.
if (set_) {
// Store the previous break is and frame id.
break_id_ = Top::break_id();
break_frame_id_ = Top::break_frame_id();
// Create the new break info.
Top::new_break(it_.frame()->id());
}
// Make sure that debugger is loaded and enter the debugger context.
load_failed_ = !Debug::Load();
if (!load_failed_) {
// NOTE the member variable save which saves the previous context before
// this change.
Top::set_context(*Debug::debug_context());
}
}
~EnterDebugger() {
if (set_) {
// Restore to the previous break state.
Top::set_break(break_frame_id_, break_id_);
}
}
// Check whether the debugger could be entered.
inline bool FailedToEnter() { return load_failed_; }
private:
JavaScriptFrameIterator it_;
const bool set_; // Was the break actually set?
StackFrame::Id break_frame_id_; // Previous break frame id.
int break_id_; // Previous break id.
bool load_failed_; // Did the debugger fail to load?
SaveContext save_; // Saves previous context.
};
// Stack allocated class for disabling break.
class DisableBreak BASE_EMBEDDED {
public:
// Enter the debugger by storing the previous top context and setting the
// current top context to the debugger context.
explicit DisableBreak(bool disable_break) {
prev_disable_break_ = Debug::disable_break();
Debug::set_disable_break(disable_break);
}
~DisableBreak() {
Debug::set_disable_break(prev_disable_break_);
}
private:
// The previous state of the disable break used to restore the value when this
// object is destructed.
bool prev_disable_break_;
};
// Debug_Address encapsulates the Address pointers used in generating debug
// code.
class Debug_Address {
public:
Debug_Address(Debug::AddressId id, int reg = 0)
: id_(id), reg_(reg) {
ASSERT(reg == 0 || id == Debug::k_register_address);
}
static Debug_Address AfterBreakTarget() {
return Debug_Address(Debug::k_after_break_target_address);
}
static Debug_Address DebugBreakReturn() {
return Debug_Address(Debug::k_debug_break_return_address);
}
static Debug_Address Register(int reg) {
return Debug_Address(Debug::k_register_address, reg);
}
Address address() const {
switch (id_) {
case Debug::k_after_break_target_address:
return reinterpret_cast<Address>(Debug::after_break_target_address());
case Debug::k_debug_break_return_address:
return reinterpret_cast<Address>(Debug::debug_break_return_address());
case Debug::k_register_address:
return reinterpret_cast<Address>(Debug::register_address(reg_));
default:
UNREACHABLE();
return NULL;
}
}
private:
Debug::AddressId id_;
int reg_;
};
} } // namespace v8::internal
#endif // V8_V8_DEBUG_H_

View File

@ -1,937 +0,0 @@
// Copyright 2007-2008 the V8 project 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.
#include <assert.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#ifndef WIN32
#include <stdint.h>
#endif
#include "v8.h"
#include "disasm.h"
#include "macro-assembler.h"
#include "platform.h"
namespace assembler { namespace arm {
namespace v8i = v8::internal;
//------------------------------------------------------------------------------
// Decoder decodes and disassembles instructions into an output buffer.
// It uses the converter to convert register names and call destinations into
// more informative description.
class Decoder {
public:
Decoder(const disasm::NameConverter& converter,
v8::internal::Vector<char> out_buffer)
: converter_(converter),
out_buffer_(out_buffer),
out_buffer_pos_(0) {
out_buffer_[out_buffer_pos_] = '\0';
}
~Decoder() {}
// Writes one disassembled instruction into 'buffer' (0-terminated).
// Returns the length of the disassembled machine instruction in bytes.
int InstructionDecode(byte* instruction);
private:
const disasm::NameConverter& converter_;
v8::internal::Vector<char> out_buffer_;
int out_buffer_pos_;
void PrintChar(const char ch);
void Print(const char* str);
void PrintRegister(int reg);
void PrintCondition(Instr* instr);
void PrintShiftRm(Instr* instr);
void PrintShiftImm(Instr* instr);
int FormatOption(Instr* instr, const char* option);
void Format(Instr* instr, const char* format);
void Unknown(Instr* instr);
void DecodeType0(Instr* instr);
void DecodeType1(Instr* instr);
void DecodeType2(Instr* instr);
void DecodeType3(Instr* instr);
void DecodeType4(Instr* instr);
void DecodeType5(Instr* instr);
void DecodeType6(Instr* instr);
void DecodeType7(Instr* instr);
};
// Append the ch to the output buffer.
void Decoder::PrintChar(const char ch) {
out_buffer_[out_buffer_pos_++] = ch;
}
// Append the str to the output buffer.
void Decoder::Print(const char* str) {
char cur = *str++;
while (cur != 0 && (out_buffer_pos_ < (out_buffer_.length()-1))) {
PrintChar(cur);
cur = *str++;
}
out_buffer_[out_buffer_pos_] = 0;
}
static const char* cond_names[16] = {
"eq", "ne", "cs" , "cc" , "mi" , "pl" , "vs" , "vc" ,
"hi", "ls", "ge", "lt", "gt", "le", "", "invalid",
};
// Print the condition guarding the instruction.
void Decoder::PrintCondition(Instr* instr) {
Print(cond_names[instr->ConditionField()]);
}
// Print the register name according to the active name converter.
void Decoder::PrintRegister(int reg) {
Print(converter_.NameOfCPURegister(reg));
}
static const char* shift_names[4] = {
"lsl", "lsr", "asr", "ror"
};
// Print the register shift operands for the instruction. Generally used for
// data processing instructions.
void Decoder::PrintShiftRm(Instr* instr) {
Shift shift = instr->ShiftField();
int shift_amount = instr->ShiftAmountField();
int rm = instr->RmField();
PrintRegister(rm);
if ((instr->RegShiftField() == 0) && (shift == LSL) && (shift_amount == 0)) {
// Special case for using rm only.
return;
}
if (instr->RegShiftField() == 0) {
// by immediate
if ((shift == ROR) && (shift_amount == 0)) {
Print(", RRX");
return;
} else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) {
shift_amount = 32;
}
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
", %s #%d",
shift_names[shift], shift_amount);
} else {
// by register
int rs = instr->RsField();
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
", %s ", shift_names[shift]);
PrintRegister(rs);
}
}
// Print the immediate operand for the instruction. Generally used for data
// processing instructions.
void Decoder::PrintShiftImm(Instr* instr) {
int rotate = instr->RotateField() * 2;
int immed8 = instr->Immed8Field();
int imm = (immed8 >> rotate) | (immed8 << (32 - rotate));
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
"#%d", imm);
}
// FormatOption takes a formatting string and interprets it based on
// the current instructions. The format string points to the first
// character of the option string (the option escape has already been
// consumed by the caller.) FormatOption returns the number of
// characters that were consumed from the formatting string.
int Decoder::FormatOption(Instr* instr, const char* format) {
switch (format[0]) {
case 'a': { // 'a: accumulate multiplies
if (instr->Bit(21) == 0) {
Print("ul");
} else {
Print("la");
}
return 1;
break;
}
case 'b': { // 'b: byte loads or stores
if (instr->HasB()) {
Print("b");
}
return 1;
break;
}
case 'c': { // 'cond: conditional execution
ASSERT((format[1] == 'o') && (format[2] == 'n') && (format[3] =='d'));
PrintCondition(instr);
return 4;
break;
}
case 'h': { // 'h: halfword operation for extra loads and stores
if (instr->HasH()) {
Print("h");
} else {
Print("b");
}
return 1;
break;
}
case 'i': { // 'imm: immediate value for data processing instructions
ASSERT((format[1] == 'm') && (format[2] == 'm'));
PrintShiftImm(instr);
return 3;
break;
}
case 'l': { // 'l: branch and link
if (instr->HasLink()) {
Print("l");
}
return 1;
break;
}
case 'm': { // 'msg: for simulator break instructions
if (format[1] == 'e') {
ASSERT((format[2] == 'm') && (format[3] == 'o') && (format[4] == 'p'));
if (instr->HasL()) {
Print("ldr");
} else {
Print("str");
}
return 5;
} else {
ASSERT(format[1] == 's' && format[2] == 'g');
byte* str =
reinterpret_cast<byte*>(instr->InstructionBits() & 0x0fffffff);
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
"%s", converter_.NameInCode(str));
return 3;
}
break;
}
case 'o': {
ASSERT(format[1] == 'f' && format[2] == 'f');
if (format[3] == '1') {
// 'off12: 12-bit offset for load and store instructions
ASSERT(format[4] == '2');
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
"%d", instr->Offset12Field());
return 5;
} else {
// 'off8: 8-bit offset for extra load and store instructions
ASSERT(format[3] == '8');
int offs8 = (instr->ImmedHField() << 4) | instr->ImmedLField();
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
"%d", offs8);
return 4;
}
break;
}
case 'p': { // 'pu: P and U bits for load and store instructions
ASSERT(format[1] == 'u');
switch (instr->PUField()) {
case 0: {
Print("da");
break;
}
case 1: {
Print("ia");
break;
}
case 2: {
Print("db");
break;
}
case 3: {
Print("ib");
break;
}
default: {
UNREACHABLE();
break;
}
}
return 2;
break;
}
case 'r': {
if (format[1] == 'n') { // 'rn: Rn register
int reg = instr->RnField();
PrintRegister(reg);
return 2;
} else if (format[1] == 'd') { // 'rd: Rd register
int reg = instr->RdField();
PrintRegister(reg);
return 2;
} else if (format[1] == 's') { // 'rs: Rs register
int reg = instr->RsField();
PrintRegister(reg);
return 2;
} else if (format[1] == 'm') { // 'rm: Rm register
int reg = instr->RmField();
PrintRegister(reg);
return 2;
} else if (format[1] == 'l') {
// 'rlist: register list for load and store multiple instructions
ASSERT(format[2] == 'i' && format[3] == 's' && format[4] == 't');
int rlist = instr->RlistField();
int reg = 0;
Print("{");
while (rlist != 0) {
if ((rlist & 1) != 0) {
PrintRegister(reg);
if ((rlist >> 1) != 0) {
Print(", ");
}
}
reg++;
rlist >>= 1;
}
Print("}");
return 5;
} else {
UNREACHABLE();
}
UNREACHABLE();
return -1;
break;
}
case 's': {
if (format[1] == 'h') { // 'shift_rm: register shift operands
ASSERT(format[2] == 'i' && format[3] == 'f' && format[4] == 't'
&& format[5] == '_' && format[6] == 'r' && format[7] == 'm');
PrintShiftRm(instr);
return 8;
} else if (format[1] == 'w') {
ASSERT(format[2] == 'i');
SoftwareInterruptCodes swi = instr->SwiField();
switch (swi) {
case call_rt_r5:
Print("call_rt_r5");
break;
case call_rt_r2:
Print("call_rt_r2");
break;
case break_point:
Print("break_point");
break;
default:
out_buffer_pos_ += v8i::OS::SNPrintF(
out_buffer_ + out_buffer_pos_,
"%d",
swi);
break;
}
return 3;
} else if (format[1] == 'i') { // 'sign: signed extra loads and stores
ASSERT(format[2] == 'g' && format[3] == 'n');
if (instr->HasSign()) {
Print("s");
}
return 4;
break;
} else { // 's: S field of data processing instructions
if (instr->HasS()) {
Print("s");
}
return 1;
}
break;
}
case 't': { // 'target: target of branch instructions
ASSERT(format[1] == 'a' && format[2] == 'r' && format[3] == 'g'
&& format[4] == 'e' && format[5] == 't');
int off = (instr->SImmed24Field() << 2) + 8;
out_buffer_pos_ += v8i::OS::SNPrintF(
out_buffer_ + out_buffer_pos_,
"%+d -> %s",
off,
converter_.NameOfAddress(reinterpret_cast<byte*>(instr) + off));
return 6;
break;
}
case 'u': { // 'u: signed or unsigned multiplies
if (instr->Bit(22) == 0) {
Print("u");
} else {
Print("s");
}
return 1;
break;
}
case 'w': { // 'w: W field of load and store instructions
if (instr->HasW()) {
Print("!");
}
return 1;
break;
}
default: {
UNREACHABLE();
break;
}
}
UNREACHABLE();
return -1;
}
// Format takes a formatting string for a whole instruction and prints it into
// the output buffer. All escaped options are handed to FormatOption to be
// parsed further.
void Decoder::Format(Instr* instr, const char* format) {
char cur = *format++;
while ((cur != 0) && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
if (cur == '\'') { // Single quote is used as the formatting escape.
format += FormatOption(instr, format);
} else {
out_buffer_[out_buffer_pos_++] = cur;
}
cur = *format++;
}
out_buffer_[out_buffer_pos_] = '\0';
}
// For currently unimplemented decodings the disassembler calls Unknown(instr)
// which will just print "unknown" of the instruction bits.
void Decoder::Unknown(Instr* instr) {
Format(instr, "unknown");
}
void Decoder::DecodeType0(Instr* instr) {
if (instr->IsSpecialType0()) {
// multiply instruction or extra loads and stores
if (instr->Bits(7, 4) == 9) {
if (instr->Bit(24) == 0) {
// multiply instructions
if (instr->Bit(23) == 0) {
if (instr->Bit(21) == 0) {
Format(instr, "mul'cond's 'rd, 'rm, 'rs");
} else {
Format(instr, "mla'cond's 'rd, 'rm, 'rs, 'rn");
}
} else {
Format(instr, "'um'al'cond's 'rn, 'rd, 'rs, 'rm");
}
} else {
Unknown(instr); // not used by V8
}
} else {
// extra load/store instructions
switch (instr->PUField()) {
case 0: {
if (instr->Bit(22) == 0) {
Format(instr, "'memop'cond'sign'h 'rd, ['rn], -'rm");
} else {
Format(instr, "'memop'cond'sign'h 'rd, ['rn], #-'off8");
}
break;
}
case 1: {
if (instr->Bit(22) == 0) {
Format(instr, "'memop'cond'sign'h 'rd, ['rn], +'rm");
} else {
Format(instr, "'memop'cond'sign'h 'rd, ['rn], #+'off8");
}
break;
}
case 2: {
if (instr->Bit(22) == 0) {
Format(instr, "'memop'cond'sign'h 'rd, ['rn, -'rm]'w");
} else {
Format(instr, "'memop'cond'sign'h 'rd, ['rn, #-'off8]'w");
}
break;
}
case 3: {
if (instr->Bit(22) == 0) {
Format(instr, "'memop'cond'sign'h 'rd, ['rn, +'rm]'w");
} else {
Format(instr, "'memop'cond'sign'h 'rd, ['rn, #+'off8]'w");
}
break;
}
default: {
// The PU field is a 2-bit field.
UNREACHABLE();
break;
}
}
return;
}
} else {
switch (instr->OpcodeField()) {
case AND: {
Format(instr, "and'cond's 'rd, 'rn, 'shift_rm");
break;
}
case EOR: {
Format(instr, "eor'cond's 'rd, 'rn, 'shift_rm");
break;
}
case SUB: {
Format(instr, "sub'cond's 'rd, 'rn, 'shift_rm");
break;
}
case RSB: {
Format(instr, "rsb'cond's 'rd, 'rn, 'shift_rm");
break;
}
case ADD: {
Format(instr, "add'cond's 'rd, 'rn, 'shift_rm");
break;
}
case ADC: {
Format(instr, "adc'cond's 'rd, 'rn, 'shift_rm");
break;
}
case SBC: {
Format(instr, "sbc'cond's 'rd, 'rn, 'shift_rm");
break;
}
case RSC: {
Format(instr, "rsc'cond's 'rd, 'rn, 'shift_rm");
break;
}
case TST: {
if (instr->HasS()) {
Format(instr, "tst'cond 'rn, 'shift_rm");
} else {
Unknown(instr); // not used by V8
return;
}
break;
}
case TEQ: {
if (instr->HasS()) {
Format(instr, "teq'cond 'rn, 'shift_rm");
} else {
Unknown(instr); // not used by V8
return;
}
break;
}
case CMP: {
if (instr->HasS()) {
Format(instr, "cmp'cond 'rn, 'shift_rm");
} else {
Unknown(instr); // not used by V8
return;
}
break;
}
case CMN: {
if (instr->HasS()) {
Format(instr, "cmn'cond 'rn, 'shift_rm");
} else {
Unknown(instr); // not used by V8
return;
}
break;
}
case ORR: {
Format(instr, "orr'cond's 'rd, 'rn, 'shift_rm");
break;
}
case MOV: {
Format(instr, "mov'cond's 'rd, 'shift_rm");
break;
}
case BIC: {
Format(instr, "bic'cond's 'rd, 'rn, 'shift_rm");
break;
}
case MVN: {
Format(instr, "mvn'cond's 'rd, 'shift_rm");
break;
}
default: {
// The Opcode field is a 4-bit field.
UNREACHABLE();
break;
}
}
}
}
void Decoder::DecodeType1(Instr* instr) {
switch (instr->OpcodeField()) {
case AND: {
Format(instr, "and'cond's 'rd, 'rn, 'imm");
break;
}
case EOR: {
Format(instr, "eor'cond's 'rd, 'rn, 'imm");
break;
}
case SUB: {
Format(instr, "sub'cond's 'rd, 'rn, 'imm");
break;
}
case RSB: {
Format(instr, "rsb'cond's 'rd, 'rn, 'imm");
break;
}
case ADD: {
Format(instr, "add'cond's 'rd, 'rn, 'imm");
break;
}
case ADC: {
Format(instr, "adc'cond's 'rd, 'rn, 'imm");
break;
}
case SBC: {
Format(instr, "sbc'cond's 'rd, 'rn, 'imm");
break;
}
case RSC: {
Format(instr, "rsc'cond's 'rd, 'rn, 'imm");
break;
}
case TST: {
if (instr->HasS()) {
Format(instr, "tst'cond 'rn, 'imm");
} else {
Unknown(instr); // not used by V8
return;
}
break;
}
case TEQ: {
if (instr->HasS()) {
Format(instr, "teq'cond 'rn, 'imm");
} else {
Unknown(instr); // not used by V8
return;
}
break;
}
case CMP: {
if (instr->HasS()) {
Format(instr, "cmp'cond 'rn, 'imm");
} else {
Unknown(instr); // not used by V8
return;
}
break;
}
case CMN: {
if (instr->HasS()) {
Format(instr, "cmn'cond 'rn, 'imm");
} else {
Unknown(instr); // not used by V8
return;
}
break;
}
case ORR: {
Format(instr, "orr'cond's 'rd, 'rn, 'imm");
break;
}
case MOV: {
Format(instr, "mov'cond's 'rd, 'imm");
break;
}
case BIC: {
Format(instr, "bic'cond's 'rd, 'rn, 'imm");
break;
}
case MVN: {
Format(instr, "mvn'cond's 'rd, 'imm");
break;
}
default: {
// The Opcode field is a 4-bit field.
UNREACHABLE();
break;
}
}
}
void Decoder::DecodeType2(Instr* instr) {
switch (instr->PUField()) {
case 0: {
if (instr->HasW()) {
Unknown(instr); // not used in V8
return;
}
Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12");
break;
}
case 1: {
if (instr->HasW()) {
Unknown(instr); // not used in V8
return;
}
Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12");
break;
}
case 2: {
Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w");
break;
}
case 3: {
Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w");
break;
}
default: {
// The PU field is a 2-bit field.
UNREACHABLE();
break;
}
}
}
void Decoder::DecodeType3(Instr* instr) {
switch (instr->PUField()) {
case 0: {
ASSERT(!instr->HasW());
Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm");
break;
}
case 1: {
ASSERT(!instr->HasW());
Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm");
break;
}
case 2: {
Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w");
break;
}
case 3: {
Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w");
break;
}
default: {
// The PU field is a 2-bit field.
UNREACHABLE();
break;
}
}
}
void Decoder::DecodeType4(Instr* instr) {
ASSERT(instr->Bit(22) == 0); // Privileged mode currently not supported.
if (instr->HasL()) {
Format(instr, "ldm'cond'pu 'rn'w, 'rlist");
} else {
Format(instr, "stm'cond'pu 'rn'w, 'rlist");
}
}
void Decoder::DecodeType5(Instr* instr) {
Format(instr, "b'l'cond 'target");
}
void Decoder::DecodeType6(Instr* instr) {
// Coprocessor instructions currently not supported.
Unknown(instr);
}
void Decoder::DecodeType7(Instr* instr) {
if (instr->Bit(24) == 1) {
Format(instr, "swi'cond 'swi");
} else {
// Coprocessor instructions currently not supported.
Unknown(instr);
}
}
// Disassemble the instruction at *instr_ptr into the output buffer.
int Decoder::InstructionDecode(byte* instr_ptr) {
Instr* instr = Instr::At(instr_ptr);
// Print raw instruction bytes.
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
"%08x ",
instr->InstructionBits());
if (instr->ConditionField() == special_condition) {
Format(instr, "break 'msg");
return Instr::kInstrSize;
}
switch (instr->TypeField()) {
case 0: {
DecodeType0(instr);
break;
}
case 1: {
DecodeType1(instr);
break;
}
case 2: {
DecodeType2(instr);
break;
}
case 3: {
DecodeType3(instr);
break;
}
case 4: {
DecodeType4(instr);
break;
}
case 5: {
DecodeType5(instr);
break;
}
case 6: {
DecodeType6(instr);
break;
}
case 7: {
DecodeType7(instr);
break;
}
default: {
// The type field is 3-bits in the ARM encoding.
UNREACHABLE();
break;
}
}
return Instr::kInstrSize;
}
} } // namespace assembler::arm
//------------------------------------------------------------------------------
namespace disasm {
static const char* reg_names[16] = {
"r0", "r1", "r2" , "r3" , "r4" , "r5" , "r6" , "r7" ,
"r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc",
};
const char* NameConverter::NameOfAddress(byte* addr) const {
static v8::internal::EmbeddedVector<char, 32> tmp_buffer;
v8::internal::OS::SNPrintF(tmp_buffer, "%p", addr);
return tmp_buffer.start();
}
const char* NameConverter::NameOfConstant(byte* addr) const {
return NameOfAddress(addr);
}
const char* NameConverter::NameOfCPURegister(int reg) const {
const char* result;
if ((0 <= reg) && (reg < 16)) {
result = reg_names[reg];
} else {
result = "noreg";
}
return result;
}
const char* NameConverter::NameOfXMMRegister(int reg) const {
UNREACHABLE(); // ARM does not have any XMM registers
return "noxmmreg";
}
const char* NameConverter::NameInCode(byte* addr) const {
// The default name converter is called for unknown code. So we will not try
// to access any memory.
return "";
}
//------------------------------------------------------------------------------
static NameConverter defaultConverter;
Disassembler::Disassembler() : converter_(defaultConverter) {}
Disassembler::Disassembler(const NameConverter& converter)
: converter_(converter) {}
Disassembler::~Disassembler() {}
int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
byte* instruction) {
assembler::arm::Decoder d(converter_, buffer);
return d.InstructionDecode(instruction);
}
int Disassembler::ConstantPoolSizeAt(byte* instruction) {
int instruction_bits = *(reinterpret_cast<int*>(instruction));
if ((instruction_bits & 0xfff00000) == 0x03000000) {
return instruction_bits & 0x0000ffff;
} else {
return -1;
}
}
void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
Disassembler d;
for (byte* pc = begin; pc < end;) {
v8::internal::EmbeddedVector<char, 128> buffer;
buffer[0] = '\0';
byte* prev_pc = pc;
pc += d.InstructionDecode(buffer, pc);
fprintf(f, "%p %08x %s\n",
prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer.start());
}
}
} // namespace disasm

File diff suppressed because it is too large Load Diff

View File

@ -1,77 +0,0 @@
// Copyright 2007-2008 the V8 project 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.
#ifndef V8_DISASM_H_
#define V8_DISASM_H_
namespace disasm {
typedef unsigned char byte;
// Interface and default implementation for converting addresses and
// register-numbers to text. The default implementation is machine
// specific.
class NameConverter {
public:
virtual ~NameConverter() {}
virtual const char* NameOfCPURegister(int reg) const;
virtual const char* NameOfXMMRegister(int reg) const;
virtual const char* NameOfAddress(byte* addr) const;
virtual const char* NameOfConstant(byte* addr) const;
virtual const char* NameInCode(byte* addr) const;
};
// A generic Disassembler interface
class Disassembler {
public:
// Uses default NameConverter.
Disassembler();
// Caller deallocates converter.
explicit Disassembler(const NameConverter& converter);
virtual ~Disassembler();
// Writes one disassembled instruction into 'buffer' (0-terminated).
// Returns the length of the disassembled machine instruction in bytes.
int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
// Returns -1 if instruction does not mark the beginning of a constant pool,
// or the number of entries in the constant pool beginning here.
int ConstantPoolSizeAt(byte* instruction);
// Write disassembly into specified file 'f' using specified NameConverter
// (see constructor).
static void Disassemble(FILE* f, byte* begin, byte* end);
private:
const NameConverter& converter_;
};
} // namespace disasm
#endif // V8_DISASM_H_

View File

@ -1,309 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#include "v8.h"
#include "code-stubs.h"
#include "codegen.h"
#include "debug.h"
#include "disasm.h"
#include "disassembler.h"
#include "macro-assembler.h"
#include "serialize.h"
#include "string-stream.h"
namespace v8 { namespace internal {
#ifdef ENABLE_DISASSEMBLER
void Disassembler::Dump(FILE* f, byte* begin, byte* end) {
for (byte* pc = begin; pc < end; pc++) {
if (f == NULL) {
PrintF("%p %4d %02x\n", pc, pc - begin, *pc);
} else {
fprintf(f, "%p %4d %02x\n", pc, pc - begin, *pc);
}
}
}
class V8NameConverter: public disasm::NameConverter {
public:
explicit V8NameConverter(Code* code) : code_(code) {}
virtual const char* NameOfAddress(byte* pc) const;
virtual const char* NameInCode(byte* addr) const;
Code* code() const { return code_; }
private:
Code* code_;
};
const char* V8NameConverter::NameOfAddress(byte* pc) const {
static v8::internal::EmbeddedVector<char, 128> buffer;
const char* name = Builtins::Lookup(pc);
if (name != NULL) {
OS::SNPrintF(buffer, "%s (%p)", name, pc);
return buffer.start();
}
if (code_ != NULL) {
int offs = pc - code_->instruction_start();
// print as code offset, if it seems reasonable
if (0 <= offs && offs < code_->instruction_size()) {
OS::SNPrintF(buffer, "%d (%p)", offs, pc);
return buffer.start();
}
}
return disasm::NameConverter::NameOfAddress(pc);
}
const char* V8NameConverter::NameInCode(byte* addr) const {
// The V8NameConverter is used for well known code, so we can "safely"
// dereference pointers in generated code.
return (code_ != NULL) ? reinterpret_cast<const char*>(addr) : "";
}
static void DumpBuffer(FILE* f, char* buff) {
if (f == NULL) {
PrintF("%s", buff);
} else {
fprintf(f, "%s", buff);
}
}
static const int kOutBufferSize = 256 + String::kMaxShortPrintLength;
static const int kRelocInfoPosition = 57;
static int DecodeIt(FILE* f,
const V8NameConverter& converter,
byte* begin,
byte* end) {
NoHandleAllocation ha;
AssertNoAllocation no_alloc;
ExternalReferenceEncoder ref_encoder;
v8::internal::EmbeddedVector<char, 128> decode_buffer;
v8::internal::EmbeddedVector<char, kOutBufferSize> out_buffer;
byte* pc = begin;
disasm::Disassembler d(converter);
RelocIterator* it = NULL;
if (converter.code() != NULL) {
it = new RelocIterator(converter.code());
} else {
// No relocation information when printing code stubs.
}
int constants = -1; // no constants being decoded at the start
while (pc < end) {
// First decode instruction so that we know its length.
byte* prev_pc = pc;
if (constants > 0) {
OS::SNPrintF(decode_buffer,
"%08x constant",
*reinterpret_cast<int32_t*>(pc));
constants--;
pc += 4;
} else {
int num_const = d.ConstantPoolSizeAt(pc);
if (num_const >= 0) {
OS::SNPrintF(decode_buffer,
"%08x constant pool begin",
*reinterpret_cast<int32_t*>(pc));
constants = num_const;
pc += 4;
} else if (it != NULL && !it->done() && it->rinfo()->pc() == pc &&
it->rinfo()->rmode() == RelocInfo::INTERNAL_REFERENCE) {
// raw pointer embedded in code stream, e.g., jump table
byte* ptr = *reinterpret_cast<byte**>(pc);
OS::SNPrintF(decode_buffer,
"%08x jump table entry %4d",
reinterpret_cast<int32_t>(ptr),
ptr - begin);
pc += 4;
} else {
decode_buffer[0] = '\0';
pc += d.InstructionDecode(decode_buffer, pc);
}
}
// Collect RelocInfo for this instruction (prev_pc .. pc-1)
List<const char*> comments(4);
List<byte*> pcs(1);
List<RelocInfo::Mode> rmodes(1);
List<intptr_t> datas(1);
if (it != NULL) {
while (!it->done() && it->rinfo()->pc() < pc) {
if (RelocInfo::IsComment(it->rinfo()->rmode())) {
// For comments just collect the text.
comments.Add(reinterpret_cast<const char*>(it->rinfo()->data()));
} else {
// For other reloc info collect all data.
pcs.Add(it->rinfo()->pc());
rmodes.Add(it->rinfo()->rmode());
datas.Add(it->rinfo()->data());
}
it->next();
}
}
StringBuilder out(out_buffer.start(), out_buffer.length());
// Comments.
for (int i = 0; i < comments.length(); i++) {
out.AddFormatted(" %s\n", comments[i]);
}
// Write out comments, resets outp so that we can format the next line.
DumpBuffer(f, out.Finalize());
out.Reset();
// Instruction address and instruction offset.
out.AddFormatted("%p %4d ", prev_pc, prev_pc - begin);
// Instruction.
out.AddFormatted("%s", decode_buffer.start());
// Print all the reloc info for this instruction which are not comments.
for (int i = 0; i < pcs.length(); i++) {
// Put together the reloc info
RelocInfo relocinfo(pcs[i], rmodes[i], datas[i]);
// Indent the printing of the reloc info.
if (i == 0) {
// The first reloc info is printed after the disassembled instruction.
out.AddPadding(' ', kRelocInfoPosition - out.position());
} else {
// Additional reloc infos are printed on separate lines.
out.AddFormatted("\n");
out.AddPadding(' ', kRelocInfoPosition);
}
RelocInfo::Mode rmode = relocinfo.rmode();
if (RelocInfo::IsPosition(rmode)) {
if (RelocInfo::IsStatementPosition(rmode)) {
out.AddFormatted(" ;; debug: statement %d", relocinfo.data());
} else {
out.AddFormatted(" ;; debug: position %d", relocinfo.data());
}
} else if (rmode == RelocInfo::EMBEDDED_OBJECT) {
HeapStringAllocator allocator;
StringStream accumulator(&allocator);
relocinfo.target_object()->ShortPrint(&accumulator);
SmartPointer<char> obj_name = accumulator.ToCString();
out.AddFormatted(" ;; object: %s", *obj_name);
} else if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
const char* reference_name =
ref_encoder.NameOfAddress(*relocinfo.target_reference_address());
out.AddFormatted(" ;; external reference (%s)", reference_name);
} else if (RelocInfo::IsCodeTarget(rmode)) {
out.AddFormatted(" ;; code:");
if (rmode == RelocInfo::CONSTRUCT_CALL) {
out.AddFormatted(" constructor,");
}
Code* code = Debug::GetCodeTarget(relocinfo.target_address());
Code::Kind kind = code->kind();
if (code->is_inline_cache_stub()) {
if (rmode == RelocInfo::CODE_TARGET_CONTEXT) {
out.AddFormatted(" contextual,");
}
InlineCacheState ic_state = code->ic_state();
out.AddFormatted(" %s, %s", Code::Kind2String(kind),
Code::ICState2String(ic_state));
if (kind == Code::CALL_IC) {
out.AddFormatted(", argc = %d", code->arguments_count());
}
} else if (kind == Code::STUB) {
// Reverse lookup required as the minor key cannot be retrieved
// from the code object.
Object* obj = Heap::code_stubs()->SlowReverseLookup(code);
if (obj != Heap::undefined_value()) {
ASSERT(obj->IsSmi());
// Get the STUB key and extract major and minor key.
uint32_t key = Smi::cast(obj)->value();
uint32_t minor_key = CodeStub::MinorKeyFromKey(key);
ASSERT(code->major_key() == CodeStub::MajorKeyFromKey(key));
out.AddFormatted(" %s, %s, ",
Code::Kind2String(kind),
CodeStub::MajorName(code->major_key()));
switch (code->major_key()) {
case CodeStub::CallFunction:
out.AddFormatted("argc = %d", minor_key);
break;
case CodeStub::Runtime: {
const char* name =
RuntimeStub::GetNameFromMinorKey(minor_key);
out.AddFormatted("%s", name);
break;
}
default:
out.AddFormatted("minor: %d", minor_key);
}
}
} else {
out.AddFormatted(" %s", Code::Kind2String(kind));
}
} else {
out.AddFormatted(" ;; %s", RelocInfo::RelocModeName(rmode));
}
}
out.AddString("\n");
DumpBuffer(f, out.Finalize());
out.Reset();
}
delete it;
return pc - begin;
}
int Disassembler::Decode(FILE* f, byte* begin, byte* end) {
V8NameConverter defaultConverter(NULL);
return DecodeIt(f, defaultConverter, begin, end);
}
// Called by Code::CodePrint.
void Disassembler::Decode(FILE* f, Code* code) {
byte* begin = Code::cast(code)->instruction_start();
byte* end = begin + Code::cast(code)->instruction_size();
V8NameConverter v8NameConverter(code);
DecodeIt(f, v8NameConverter, begin, end);
}
#else // ENABLE_DISASSEMBLER
void Disassembler::Dump(FILE* f, byte* begin, byte* end) {}
int Disassembler::Decode(FILE* f, byte* begin, byte* end) { return 0; }
void Disassembler::Decode(FILE* f, Code* code) {}
#endif // ENABLE_DISASSEMBLER
} } // namespace v8::internal

View File

@ -1,55 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#ifndef V8_DISASSEMBLER_H_
#define V8_DISASSEMBLER_H_
namespace v8 { namespace internal {
class Disassembler : public AllStatic {
public:
// Print the bytes in the interval [begin, end) into f.
static void Dump(FILE* f, byte* begin, byte* end);
// Decode instructions in the the interval [begin, end) and print the
// code into f. Returns the number of bytes disassembled or 1 if no
// instruction could be decoded.
static int Decode(FILE* f, byte* begin, byte* end);
// Decode instructions in code.
static void Decode(FILE* f, Code* code);
private:
// Decode instruction at pc and print disassembled instruction into f.
// Returns the instruction length in bytes, or 1 if the instruction could
// not be decoded. The number of characters written is written into
// the out parameter char_count.
static int Decode(FILE* f, byte* pc, int* char_count);
};
} } // namespace v8::internal
#endif // V8_DISASSEMBLER_H_

View File

@ -1,66 +0,0 @@
/*
* Copyright 2007-2008 the V8 project 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.
*/
/**
* Dtoa needs to have a particular environment set up for it so
* instead of using it directly you should use this file.
*
* The way it works is that when you link with it, its definitions
* of dtoa, strtod etc. override the default ones. So if you fail
* to link with this library everything will still work, it's just
* subtly wrong.
*/
#if !(defined(__APPLE__) && defined(__MACH__)) && !defined(WIN32)
#include <endian.h>
#endif
#include <math.h>
#include <float.h>
/* The floating point word order on ARM is big endian when floating point
* emulation is used, even if the byte order is little endian */
#if !(defined(__APPLE__) && defined(__MACH__)) && !defined(WIN32) && \
__FLOAT_WORD_ORDER == __BIG_ENDIAN
#define IEEE_MC68k
#else
#define IEEE_8087
#endif
#define __MATH_H__
#if defined(__APPLE__) && defined(__MACH__)
/* stdlib.h on Apple's 10.5 and later SDKs will mangle the name of strtod.
* If it's included after strtod is redefined as gay_strtod, it will mangle
* the name of gay_strtod, which is unwanted. */
#include <stdlib.h>
#endif
/* Make sure we use the David M. Gay version of strtod(). On Linux, we
* cannot use the same name (maybe the function does not have weak
* linkage?). */
#define strtod gay_strtod
#include "third_party/dtoa/dtoa.c"

View File

@ -1,529 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#include <stdlib.h>
#include "v8.h"
#include "api.h"
#include "codegen-inl.h"
#if defined(ARM) || defined (__arm__) || defined(__thumb__)
#include "simulator-arm.h"
#else // ia32
#include "simulator-ia32.h"
#endif
namespace v8 { namespace internal {
static Handle<Object> Invoke(bool construct,
Handle<JSFunction> func,
Handle<Object> receiver,
int argc,
Object*** args,
bool* has_pending_exception) {
// Make sure we have a real function, not a boilerplate function.
ASSERT(!func->IsBoilerplate());
// Entering JavaScript.
VMState state(JS);
// Guard the stack against too much recursion.
StackGuard guard;
// Placeholder for return value.
Object* value = reinterpret_cast<Object*>(kZapValue);
typedef Object* (*JSEntryFunction)(
byte* entry,
Object* function,
Object* receiver,
int argc,
Object*** args);
Handle<Code> code;
if (construct) {
JSConstructEntryStub stub;
code = stub.GetCode();
} else {
JSEntryStub stub;
code = stub.GetCode();
}
{
// Save and restore context around invocation and block the
// allocation of handles without explicit handle scopes.
SaveContext save;
NoHandleAllocation na;
JSEntryFunction entry = FUNCTION_CAST<JSEntryFunction>(code->entry());
// Call the function through the right JS entry stub.
value = CALL_GENERATED_CODE(entry, func->code()->entry(), *func,
*receiver, argc, args);
}
#ifdef DEBUG
value->Verify();
#endif
// Update the pending exception and external caught flag and return the value.
*has_pending_exception = value->IsException();
ASSERT(*has_pending_exception == Top::has_pending_exception());
Top::propagate_external_caught();
// If the pending exception is OutOfMemoryException set out_of_memory in
// the global context. Note: We have to mark the global context here
// since the GenerateThrowOutOfMemory stub cannot make a RuntimeCall to
// set it.
if (*has_pending_exception) {
if (Top::pending_exception() == Failure::OutOfMemoryException()) {
Top::context()->mark_out_of_memory();
}
}
return Handle<Object>(value);
}
Handle<Object> Execution::Call(Handle<JSFunction> func,
Handle<Object> receiver,
int argc,
Object*** args,
bool* pending_exception) {
return Invoke(false, func, receiver, argc, args, pending_exception);
}
Handle<Object> Execution::New(Handle<JSFunction> func, int argc,
Object*** args, bool* pending_exception) {
return Invoke(true, func, Top::global(), argc, args, pending_exception);
}
Handle<Object> Execution::TryCall(Handle<JSFunction> func,
Handle<Object> receiver,
int argc,
Object*** args,
bool* caught_exception) {
// Enter a try-block while executing the JavaScript code. To avoid
// duplicate error printing it must be non-verbose. Also, to avoid
// creating message objects during stack overflow we shouldn't
// capture messages.
v8::TryCatch catcher;
catcher.SetVerbose(false);
catcher.SetCaptureMessage(false);
Handle<Object> result = Invoke(false, func, receiver, argc, args,
caught_exception);
if (*caught_exception) {
ASSERT(catcher.HasCaught());
ASSERT(Top::has_pending_exception());
ASSERT(Top::external_caught_exception());
Top::optional_reschedule_exception(true);
result = v8::Utils::OpenHandle(*catcher.Exception());
}
ASSERT(!Top::has_pending_exception());
ASSERT(!Top::external_caught_exception());
return result;
}
Handle<Object> Execution::GetFunctionDelegate(Handle<Object> object) {
ASSERT(!object->IsJSFunction());
// If you return a function from here, it will be called when an
// attempt is made to call the given object as a function.
// The regular expression code here is really meant more as an
// example than anything else. KJS does not support calling regular
// expressions as functions, but SpiderMonkey does.
if (FLAG_call_regexp) {
bool is_regexp =
object->IsHeapObject() &&
(HeapObject::cast(*object)->map()->constructor() ==
*Top::regexp_function());
if (is_regexp) {
Handle<String> exec = Factory::exec_symbol();
return Handle<Object>(object->GetProperty(*exec));
}
}
// Objects created through the API can have an instance-call handler
// that should be used when calling the object as a function.
if (object->IsHeapObject() &&
HeapObject::cast(*object)->map()->has_instance_call_handler()) {
return Handle<JSFunction>(
Top::global_context()->call_as_function_delegate());
}
return Factory::undefined_value();
}
// Static state for stack guards.
StackGuard::ThreadLocal StackGuard::thread_local_;
StackGuard::StackGuard() {
ExecutionAccess access;
if (thread_local_.nesting_++ == 0 &&
thread_local_.jslimit_ != kInterruptLimit) {
// NOTE: We assume that the stack grows towards lower addresses.
ASSERT(thread_local_.jslimit_ == kIllegalLimit);
ASSERT(thread_local_.climit_ == kIllegalLimit);
thread_local_.initial_jslimit_ = thread_local_.jslimit_ =
GENERATED_CODE_STACK_LIMIT(kLimitSize);
// NOTE: The check for overflow is not safe as there is no guarantee that
// the running thread has its stack in all memory up to address 0x00000000.
thread_local_.initial_climit_ = thread_local_.climit_ =
reinterpret_cast<uintptr_t>(this) >= kLimitSize ?
reinterpret_cast<uintptr_t>(this) - kLimitSize : 0;
if (thread_local_.interrupt_flags_ != 0) {
set_limits(kInterruptLimit, access);
}
}
// make sure we have proper limits setup
ASSERT(thread_local_.jslimit_ != kIllegalLimit &&
thread_local_.climit_ != kIllegalLimit);
}
StackGuard::~StackGuard() {
ExecutionAccess access;
if (--thread_local_.nesting_ == 0) {
set_limits(kIllegalLimit, access);
}
}
bool StackGuard::IsStackOverflow() {
ExecutionAccess access;
return (thread_local_.jslimit_ != kInterruptLimit &&
thread_local_.climit_ != kInterruptLimit);
}
void StackGuard::EnableInterrupts() {
ExecutionAccess access;
if (IsSet(access)) {
set_limits(kInterruptLimit, access);
}
}
void StackGuard::SetStackLimit(uintptr_t limit) {
ExecutionAccess access;
// If the current limits are special (eg due to a pending interrupt) then
// leave them alone.
if (thread_local_.jslimit_ == thread_local_.initial_jslimit_) {
thread_local_.jslimit_ = limit;
}
if (thread_local_.climit_ == thread_local_.initial_climit_) {
thread_local_.climit_ = limit;
}
thread_local_.initial_climit_ = limit;
thread_local_.initial_jslimit_ = limit;
}
void StackGuard::DisableInterrupts() {
ExecutionAccess access;
reset_limits(access);
}
bool StackGuard::IsSet(const ExecutionAccess& lock) {
return thread_local_.interrupt_flags_ != 0;
}
bool StackGuard::IsInterrupted() {
ExecutionAccess access;
return thread_local_.interrupt_flags_ & INTERRUPT;
}
void StackGuard::Interrupt() {
ExecutionAccess access;
thread_local_.interrupt_flags_ |= INTERRUPT;
set_limits(kInterruptLimit, access);
}
bool StackGuard::IsPreempted() {
ExecutionAccess access;
return thread_local_.interrupt_flags_ & PREEMPT;
}
void StackGuard::Preempt() {
ExecutionAccess access;
thread_local_.interrupt_flags_ |= PREEMPT;
set_limits(kInterruptLimit, access);
}
bool StackGuard::IsDebugBreak() {
ExecutionAccess access;
return thread_local_.interrupt_flags_ & DEBUGBREAK;
}
void StackGuard::DebugBreak() {
ExecutionAccess access;
thread_local_.interrupt_flags_ |= DEBUGBREAK;
set_limits(kInterruptLimit, access);
}
void StackGuard::Continue(InterruptFlag after_what) {
ExecutionAccess access;
thread_local_.interrupt_flags_ &= ~static_cast<int>(after_what);
if (thread_local_.interrupt_flags_ == 0) {
reset_limits(access);
}
}
int StackGuard::ArchiveSpacePerThread() {
return sizeof(ThreadLocal);
}
char* StackGuard::ArchiveStackGuard(char* to) {
ExecutionAccess access;
memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
ThreadLocal blank;
thread_local_ = blank;
return to + sizeof(ThreadLocal);
}
char* StackGuard::RestoreStackGuard(char* from) {
ExecutionAccess access;
memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
return from + sizeof(ThreadLocal);
}
// --- C a l l s t o n a t i v e s ---
#define RETURN_NATIVE_CALL(name, argc, argv, has_pending_exception) \
do { \
Object** args[argc] = argv; \
ASSERT(has_pending_exception != NULL); \
return Call(Top::name##_fun(), Top::builtins(), argc, args, \
has_pending_exception); \
} while (false)
Handle<Object> Execution::ToBoolean(Handle<Object> obj) {
// See the similar code in runtime.js:ToBoolean.
if (obj->IsBoolean()) return obj;
bool result = true;
if (obj->IsString()) {
result = Handle<String>::cast(obj)->length() != 0;
} else if (obj->IsNull() || obj->IsUndefined()) {
result = false;
} else if (obj->IsNumber()) {
double value = obj->Number();
result = !((value == 0) || isnan(value));
}
return Handle<Object>(Heap::ToBoolean(result));
}
Handle<Object> Execution::ToNumber(Handle<Object> obj, bool* exc) {
RETURN_NATIVE_CALL(to_number, 1, { obj.location() }, exc);
}
Handle<Object> Execution::ToString(Handle<Object> obj, bool* exc) {
RETURN_NATIVE_CALL(to_string, 1, { obj.location() }, exc);
}
Handle<Object> Execution::ToDetailString(Handle<Object> obj, bool* exc) {
RETURN_NATIVE_CALL(to_detail_string, 1, { obj.location() }, exc);
}
Handle<Object> Execution::ToObject(Handle<Object> obj, bool* exc) {
if (obj->IsJSObject()) return obj;
RETURN_NATIVE_CALL(to_object, 1, { obj.location() }, exc);
}
Handle<Object> Execution::ToInteger(Handle<Object> obj, bool* exc) {
RETURN_NATIVE_CALL(to_integer, 1, { obj.location() }, exc);
}
Handle<Object> Execution::ToUint32(Handle<Object> obj, bool* exc) {
RETURN_NATIVE_CALL(to_uint32, 1, { obj.location() }, exc);
}
Handle<Object> Execution::ToInt32(Handle<Object> obj, bool* exc) {
RETURN_NATIVE_CALL(to_int32, 1, { obj.location() }, exc);
}
Handle<Object> Execution::NewDate(double time, bool* exc) {
Handle<Object> time_obj = Factory::NewNumber(time);
RETURN_NATIVE_CALL(create_date, 1, { time_obj.location() }, exc);
}
#undef RETURN_NATIVE_CALL
Handle<Object> Execution::CharAt(Handle<String> string, uint32_t index) {
int int_index = static_cast<int>(index);
if (int_index < 0 || int_index >= string->length()) {
return Factory::undefined_value();
}
Handle<Object> char_at =
GetProperty(Top::builtins(), Factory::char_at_symbol());
if (!char_at->IsJSFunction()) {
return Factory::undefined_value();
}
bool caught_exception;
Handle<Object> index_object = Factory::NewNumberFromInt(int_index);
Object** index_arg[] = { index_object.location() };
Handle<Object> result = TryCall(Handle<JSFunction>::cast(char_at),
string,
ARRAY_SIZE(index_arg),
index_arg,
&caught_exception);
if (caught_exception) {
return Factory::undefined_value();
}
return result;
}
Handle<JSFunction> Execution::InstantiateFunction(
Handle<FunctionTemplateInfo> data, bool* exc) {
// Fast case: see if the function has already been instantiated
int serial_number = Smi::cast(data->serial_number())->value();
Object* elm =
Top::global_context()->function_cache()->GetElement(serial_number);
if (!elm->IsUndefined()) return Handle<JSFunction>(JSFunction::cast(elm));
// The function has not yet been instantiated in this context; do it.
Object** args[1] = { Handle<Object>::cast(data).location() };
Handle<Object> result =
Call(Top::instantiate_fun(), Top::builtins(), 1, args, exc);
if (*exc) return Handle<JSFunction>::null();
return Handle<JSFunction>::cast(result);
}
Handle<JSObject> Execution::InstantiateObject(Handle<ObjectTemplateInfo> data,
bool* exc) {
if (data->property_list()->IsUndefined() &&
!data->constructor()->IsUndefined()) {
Object* result;
{
HandleScope scope;
Handle<FunctionTemplateInfo> cons_template =
Handle<FunctionTemplateInfo>(
FunctionTemplateInfo::cast(data->constructor()));
Handle<JSFunction> cons = InstantiateFunction(cons_template, exc);
if (*exc) return Handle<JSObject>::null();
Handle<Object> value = New(cons, 0, NULL, exc);
if (*exc) return Handle<JSObject>::null();
result = *value;
}
ASSERT(!*exc);
return Handle<JSObject>(JSObject::cast(result));
} else {
Object** args[1] = { Handle<Object>::cast(data).location() };
Handle<Object> result =
Call(Top::instantiate_fun(), Top::builtins(), 1, args, exc);
if (*exc) return Handle<JSObject>::null();
return Handle<JSObject>::cast(result);
}
}
void Execution::ConfigureInstance(Handle<Object> instance,
Handle<Object> instance_template,
bool* exc) {
Object** args[2] = { instance.location(), instance_template.location() };
Execution::Call(Top::configure_instance_fun(), Top::builtins(), 2, args, exc);
}
Handle<String> Execution::GetStackTraceLine(Handle<Object> recv,
Handle<JSFunction> fun,
Handle<Object> pos,
Handle<Object> is_global) {
const int argc = 4;
Object** args[argc] = { recv.location(),
Handle<Object>::cast(fun).location(),
pos.location(),
is_global.location() };
bool caught_exception = false;
Handle<Object> result = TryCall(Top::get_stack_trace_line_fun(),
Top::builtins(), argc, args,
&caught_exception);
if (caught_exception || !result->IsString()) return Factory::empty_symbol();
return Handle<String>::cast(result);
}
// --- G C E x t e n s i o n ---
const char* GCExtension::kSource = "native function gc();";
v8::Handle<v8::FunctionTemplate> GCExtension::GetNativeFunction(
v8::Handle<v8::String> str) {
return v8::FunctionTemplate::New(GCExtension::GC);
}
v8::Handle<v8::Value> GCExtension::GC(const v8::Arguments& args) {
// All allocation spaces other than NEW_SPACE have the same effect.
Heap::CollectGarbage(0, OLD_DATA_SPACE);
return v8::Undefined();
}
static GCExtension kGCExtension;
v8::DeclareExtension kGCExtensionDeclaration(&kGCExtension);
} } // namespace v8::internal

View File

@ -1,262 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#ifndef V8_EXECUTION_H_
#define V8_EXECUTION_H_
namespace v8 { namespace internal {
// Flag used to set the interrupt causes.
enum InterruptFlag {
INTERRUPT = 1 << 0,
DEBUGBREAK = 1 << 1,
PREEMPT = 1 << 2
};
class Execution : public AllStatic {
public:
// Call a function, the caller supplies a receiver and an array
// of arguments. Arguments are Object* type. After function returns,
// pointers in 'args' might be invalid.
//
// *pending_exception tells whether the invoke resulted in
// a pending exception.
//
static Handle<Object> Call(Handle<JSFunction> func,
Handle<Object> receiver,
int argc,
Object*** args,
bool* pending_exception);
// Construct object from function, the caller supplies an array of
// arguments. Arguments are Object* type. After function returns,
// pointers in 'args' might be invalid.
//
// *pending_exception tells whether the invoke resulted in
// a pending exception.
//
static Handle<Object> New(Handle<JSFunction> func,
int argc,
Object*** args,
bool* pending_exception);
// Call a function, just like Call(), but make sure to silently catch
// any thrown exceptions. The return value is either the result of
// calling the function (if caught exception is false) or the exception
// that occurred (if caught exception is true).
static Handle<Object> TryCall(Handle<JSFunction> func,
Handle<Object> receiver,
int argc,
Object*** args,
bool* caught_exception);
// ECMA-262 9.2
static Handle<Object> ToBoolean(Handle<Object> obj);
// ECMA-262 9.3
static Handle<Object> ToNumber(Handle<Object> obj, bool* exc);
// ECMA-262 9.4
static Handle<Object> ToInteger(Handle<Object> obj, bool* exc);
// ECMA-262 9.5
static Handle<Object> ToInt32(Handle<Object> obj, bool* exc);
// ECMA-262 9.6
static Handle<Object> ToUint32(Handle<Object> obj, bool* exc);
// ECMA-262 9.8
static Handle<Object> ToString(Handle<Object> obj, bool* exc);
// ECMA-262 9.8
static Handle<Object> ToDetailString(Handle<Object> obj, bool* exc);
// ECMA-262 9.9
static Handle<Object> ToObject(Handle<Object> obj, bool* exc);
// Create a new date object from 'time'.
static Handle<Object> NewDate(double time, bool* exc);
// Used to implement [] notation on strings (calls JS code)
static Handle<Object> CharAt(Handle<String> str, uint32_t index);
static Handle<Object> GetFunctionFor();
static Handle<JSFunction> InstantiateFunction(
Handle<FunctionTemplateInfo> data, bool* exc);
static Handle<JSObject> InstantiateObject(Handle<ObjectTemplateInfo> data,
bool* exc);
static void ConfigureInstance(Handle<Object> instance,
Handle<Object> data,
bool* exc);
static Handle<String> GetStackTraceLine(Handle<Object> recv,
Handle<JSFunction> fun,
Handle<Object> pos,
Handle<Object> is_global);
// Get a function delegate (or undefined) for the given non-function
// object. Used for support calling objects as functions.
static Handle<Object> GetFunctionDelegate(Handle<Object> object);
};
class ExecutionAccess;
// Stack guards are used to limit the number of nested invocations of
// JavaScript and the stack size used in each invocation.
class StackGuard BASE_EMBEDDED {
public:
StackGuard();
~StackGuard();
static void SetStackLimit(uintptr_t limit);
static Address address_of_jslimit() {
return reinterpret_cast<Address>(&thread_local_.jslimit_);
}
// Threading support.
static char* ArchiveStackGuard(char* to);
static char* RestoreStackGuard(char* from);
static int ArchiveSpacePerThread();
static bool IsStackOverflow();
static bool IsPreempted();
static void Preempt();
static bool IsInterrupted();
static void Interrupt();
static bool IsDebugBreak();
static void DebugBreak();
static void Continue(InterruptFlag after_what);
private:
// You should hold the ExecutionAccess lock when calling this method.
static bool IsSet(const ExecutionAccess& lock);
// This provides an asynchronous read of the stack limit for the current
// thread. There are no locks protecting this, but it is assumed that you
// have the global V8 lock if you are using multiple V8 threads.
static uintptr_t climit() {
return thread_local_.climit_;
}
// You should hold the ExecutionAccess lock when calling this method.
static void set_limits(uintptr_t value, const ExecutionAccess& lock) {
thread_local_.jslimit_ = value;
thread_local_.climit_ = value;
}
// Reset limits to initial values. For example after handling interrupt.
// You should hold the ExecutionAccess lock when calling this method.
static void reset_limits(const ExecutionAccess& lock) {
if (thread_local_.nesting_ == 0) {
// No limits have been set yet.
set_limits(kIllegalLimit, lock);
} else {
thread_local_.jslimit_ = thread_local_.initial_jslimit_;
thread_local_.climit_ = thread_local_.initial_climit_;
}
}
// Enable or disable interrupts.
static void EnableInterrupts();
static void DisableInterrupts();
static const uintptr_t kLimitSize = 512 * KB;
static const uintptr_t kInterruptLimit = 0xfffffffe;
static const uintptr_t kIllegalLimit = 0xffffffff;
class ThreadLocal {
public:
ThreadLocal()
: initial_jslimit_(kIllegalLimit),
jslimit_(kIllegalLimit),
initial_climit_(kIllegalLimit),
climit_(kIllegalLimit),
nesting_(0),
postpone_interrupts_nesting_(0),
interrupt_flags_(0) {}
uintptr_t initial_jslimit_;
uintptr_t jslimit_;
uintptr_t initial_climit_;
uintptr_t climit_;
int nesting_;
int postpone_interrupts_nesting_;
int interrupt_flags_;
};
static ThreadLocal thread_local_;
friend class StackLimitCheck;
friend class PostponeInterruptsScope;
};
// Support for checking for stack-overflows in C++ code.
class StackLimitCheck BASE_EMBEDDED {
public:
bool HasOverflowed() const {
return reinterpret_cast<uintptr_t>(this) < StackGuard::climit();
}
};
// Support for temporarily postponing interrupts. When the outermost
// postpone scope is left the interrupts will be re-enabled and any
// interrupts that occurred while in the scope will be taken into
// account.
class PostponeInterruptsScope BASE_EMBEDDED {
public:
PostponeInterruptsScope() {
StackGuard::thread_local_.postpone_interrupts_nesting_++;
StackGuard::DisableInterrupts();
}
~PostponeInterruptsScope() {
if (--StackGuard::thread_local_.postpone_interrupts_nesting_ == 0) {
StackGuard::EnableInterrupts();
}
}
};
class GCExtension : public v8::Extension {
public:
GCExtension() : v8::Extension("v8/gc", kSource) {}
virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
v8::Handle<v8::String> name);
static v8::Handle<v8::Value> GC(const v8::Arguments& args);
private:
static const char* kSource;
};
} } // namespace v8::internal
#endif // V8_EXECUTION_H_

View File

@ -1,841 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#include "v8.h"
#include "api.h"
#include "debug.h"
#include "execution.h"
#include "factory.h"
#include "macro-assembler.h"
namespace v8 { namespace internal {
Handle<FixedArray> Factory::NewFixedArray(int size, PretenureFlag pretenure) {
ASSERT(0 <= size);
CALL_HEAP_FUNCTION(Heap::AllocateFixedArray(size, pretenure), FixedArray);
}
Handle<DescriptorArray> Factory::NewDescriptorArray(int number_of_descriptors) {
ASSERT(0 <= number_of_descriptors);
CALL_HEAP_FUNCTION(DescriptorArray::Allocate(number_of_descriptors),
DescriptorArray);
}
// Symbols are created in the old generation (data space).
Handle<String> Factory::LookupSymbol(Vector<const char> string) {
CALL_HEAP_FUNCTION(Heap::LookupSymbol(string), String);
}
Handle<String> Factory::NewStringFromAscii(Vector<const char> string,
PretenureFlag pretenure) {
CALL_HEAP_FUNCTION(Heap::AllocateStringFromAscii(string, pretenure), String);
}
Handle<String> Factory::NewStringFromUtf8(Vector<const char> string,
PretenureFlag pretenure) {
CALL_HEAP_FUNCTION(Heap::AllocateStringFromUtf8(string, pretenure), String);
}
Handle<String> Factory::NewStringFromTwoByte(Vector<const uc16> string) {
CALL_HEAP_FUNCTION(Heap::AllocateStringFromTwoByte(string), String);
}
Handle<String> Factory::NewRawTwoByteString(int length,
PretenureFlag pretenure) {
CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(length, pretenure), String);
}
Handle<String> Factory::NewConsString(Handle<String> first,
Handle<String> second) {
if (first->length() == 0) return second;
if (second->length() == 0) return first;
CALL_HEAP_FUNCTION(Heap::AllocateConsString(*first, *second), String);
}
Handle<String> Factory::NewStringSlice(Handle<String> str, int begin, int end) {
CALL_HEAP_FUNCTION(str->Slice(begin, end), String);
}
Handle<String> Factory::NewExternalStringFromAscii(
ExternalAsciiString::Resource* resource) {
CALL_HEAP_FUNCTION(Heap::AllocateExternalStringFromAscii(resource), String);
}
Handle<String> Factory::NewExternalStringFromTwoByte(
ExternalTwoByteString::Resource* resource) {
CALL_HEAP_FUNCTION(Heap::AllocateExternalStringFromTwoByte(resource), String);
}
Handle<Context> Factory::NewGlobalContext() {
CALL_HEAP_FUNCTION(Heap::AllocateGlobalContext(), Context);
}
Handle<Context> Factory::NewFunctionContext(int length,
Handle<JSFunction> closure) {
CALL_HEAP_FUNCTION(Heap::AllocateFunctionContext(length, *closure), Context);
}
Handle<Context> Factory::NewWithContext(Handle<Context> previous,
Handle<JSObject> extension) {
CALL_HEAP_FUNCTION(Heap::AllocateWithContext(*previous, *extension), Context);
}
Handle<Struct> Factory::NewStruct(InstanceType type) {
CALL_HEAP_FUNCTION(Heap::AllocateStruct(type), Struct);
}
Handle<AccessorInfo> Factory::NewAccessorInfo() {
Handle<AccessorInfo> info =
Handle<AccessorInfo>::cast(NewStruct(ACCESSOR_INFO_TYPE));
info->set_flag(0); // Must clear the flag, it was initialized as undefined.
return info;
}
Handle<Script> Factory::NewScript(Handle<String> source) {
Handle<Script> script = Handle<Script>::cast(NewStruct(SCRIPT_TYPE));
script->set_source(*source);
script->set_name(Heap::undefined_value());
script->set_line_offset(Smi::FromInt(0));
script->set_column_offset(Smi::FromInt(0));
script->set_wrapper(*Factory::NewProxy(0, TENURED));
script->set_type(Smi::FromInt(SCRIPT_TYPE_NORMAL));
return script;
}
Handle<Proxy> Factory::NewProxy(Address addr, PretenureFlag pretenure) {
CALL_HEAP_FUNCTION(Heap::AllocateProxy(addr, pretenure), Proxy);
}
Handle<Proxy> Factory::NewProxy(const AccessorDescriptor* desc) {
return NewProxy((Address) desc, TENURED);
}
Handle<ByteArray> Factory::NewByteArray(int length) {
ASSERT(0 <= length);
CALL_HEAP_FUNCTION(Heap::AllocateByteArray(length), ByteArray);
}
Handle<Map> Factory::NewMap(InstanceType type, int instance_size) {
CALL_HEAP_FUNCTION(Heap::AllocateMap(type, instance_size), Map);
}
Handle<JSObject> Factory::NewFunctionPrototype(Handle<JSFunction> function) {
CALL_HEAP_FUNCTION(Heap::AllocateFunctionPrototype(*function), JSObject);
}
Handle<Map> Factory::CopyMap(Handle<Map> src) {
CALL_HEAP_FUNCTION(src->Copy(), Map);
}
Handle<Map> Factory::CopyMapDropTransitions(Handle<Map> src) {
CALL_HEAP_FUNCTION(src->CopyDropTransitions(), Map);
}
Handle<FixedArray> Factory::CopyFixedArray(Handle<FixedArray> array) {
CALL_HEAP_FUNCTION(array->Copy(), FixedArray);
}
Handle<JSFunction> Factory::BaseNewFunctionFromBoilerplate(
Handle<JSFunction> boilerplate,
Handle<Map> function_map) {
ASSERT(boilerplate->IsBoilerplate());
ASSERT(!boilerplate->has_initial_map());
ASSERT(!boilerplate->has_prototype());
ASSERT(boilerplate->properties() == Heap::empty_fixed_array());
ASSERT(boilerplate->elements() == Heap::empty_fixed_array());
CALL_HEAP_FUNCTION(Heap::AllocateFunction(*function_map,
boilerplate->shared(),
Heap::the_hole_value()),
JSFunction);
}
Handle<JSFunction> Factory::NewFunctionFromBoilerplate(
Handle<JSFunction> boilerplate,
Handle<Context> context) {
Handle<JSFunction> result =
BaseNewFunctionFromBoilerplate(boilerplate, Top::function_map());
result->set_context(*context);
int number_of_literals = boilerplate->NumberOfLiterals();
Handle<FixedArray> literals =
Factory::NewFixedArray(number_of_literals, TENURED);
if (number_of_literals > 0) {
// Store the object, regexp and array functions in the literals
// array prefix. These functions will be used when creating
// object, regexp and array literals in this function.
literals->set(JSFunction::kLiteralGlobalContextIndex,
context->global_context());
}
result->set_literals(*literals);
ASSERT(!result->IsBoilerplate());
return result;
}
Handle<Object> Factory::NewNumber(double value,
PretenureFlag pretenure) {
CALL_HEAP_FUNCTION(Heap::NumberFromDouble(value, pretenure), Object);
}
Handle<Object> Factory::NewNumberFromInt(int value) {
CALL_HEAP_FUNCTION(Heap::NumberFromInt32(value), Object);
}
Handle<JSObject> Factory::NewNeanderObject() {
CALL_HEAP_FUNCTION(Heap::AllocateJSObjectFromMap(Heap::neander_map()),
JSObject);
}
Handle<Object> Factory::NewTypeError(const char* type,
Vector< Handle<Object> > args) {
return NewError("MakeTypeError", type, args);
}
Handle<Object> Factory::NewTypeError(Handle<String> message) {
return NewError("$TypeError", message);
}
Handle<Object> Factory::NewRangeError(const char* type,
Vector< Handle<Object> > args) {
return NewError("MakeRangeError", type, args);
}
Handle<Object> Factory::NewRangeError(Handle<String> message) {
return NewError("$RangeError", message);
}
Handle<Object> Factory::NewSyntaxError(const char* type, Handle<JSArray> args) {
return NewError("MakeSyntaxError", type, args);
}
Handle<Object> Factory::NewSyntaxError(Handle<String> message) {
return NewError("$SyntaxError", message);
}
Handle<Object> Factory::NewReferenceError(const char* type,
Vector< Handle<Object> > args) {
return NewError("MakeReferenceError", type, args);
}
Handle<Object> Factory::NewReferenceError(Handle<String> message) {
return NewError("$ReferenceError", message);
}
Handle<Object> Factory::NewError(const char* maker, const char* type,
Vector< Handle<Object> > args) {
HandleScope scope;
Handle<FixedArray> array = Factory::NewFixedArray(args.length());
for (int i = 0; i < args.length(); i++) {
array->set(i, *args[i]);
}
Handle<JSArray> object = Factory::NewJSArrayWithElements(array);
Handle<Object> result = NewError(maker, type, object);
return result.EscapeFrom(&scope);
}
Handle<Object> Factory::NewEvalError(const char* type,
Vector< Handle<Object> > args) {
return NewError("MakeEvalError", type, args);
}
Handle<Object> Factory::NewError(const char* type,
Vector< Handle<Object> > args) {
return NewError("MakeError", type, args);
}
Handle<Object> Factory::NewError(const char* maker,
const char* type,
Handle<JSArray> args) {
Handle<String> make_str = Factory::LookupAsciiSymbol(maker);
Handle<JSFunction> fun =
Handle<JSFunction>(
JSFunction::cast(
Top::builtins()->GetProperty(*make_str)));
Handle<Object> type_obj = Factory::LookupAsciiSymbol(type);
Object** argv[2] = { type_obj.location(),
Handle<Object>::cast(args).location() };
// Invoke the JavaScript factory method. If an exception is thrown while
// running the factory method, use the exception as the result.
bool caught_exception;
Handle<Object> result = Execution::TryCall(fun,
Top::builtins(),
2,
argv,
&caught_exception);
return result;
}
Handle<Object> Factory::NewError(Handle<String> message) {
return NewError("$Error", message);
}
Handle<Object> Factory::NewError(const char* constructor,
Handle<String> message) {
Handle<String> constr = Factory::LookupAsciiSymbol(constructor);
Handle<JSFunction> fun =
Handle<JSFunction>(
JSFunction::cast(
Top::builtins()->GetProperty(*constr)));
Object** argv[1] = { Handle<Object>::cast(message).location() };
// Invoke the JavaScript factory method. If an exception is thrown while
// running the factory method, use the exception as the result.
bool caught_exception;
Handle<Object> result = Execution::TryCall(fun,
Top::builtins(),
1,
argv,
&caught_exception);
return result;
}
Handle<JSFunction> Factory::NewFunction(Handle<String> name,
InstanceType type,
int instance_size,
Handle<Code> code,
bool force_initial_map) {
// Allocate the function
Handle<JSFunction> function = NewFunction(name, the_hole_value());
function->set_code(*code);
if (force_initial_map ||
type != JS_OBJECT_TYPE ||
instance_size != JSObject::kHeaderSize) {
Handle<Map> initial_map = NewMap(type, instance_size);
Handle<JSObject> prototype = NewFunctionPrototype(function);
initial_map->set_prototype(*prototype);
function->set_initial_map(*initial_map);
initial_map->set_constructor(*function);
} else {
ASSERT(!function->has_initial_map());
ASSERT(!function->has_prototype());
}
return function;
}
Handle<JSFunction> Factory::NewFunctionBoilerplate(Handle<String> name,
int number_of_literals,
bool contains_array_literal,
Handle<Code> code) {
Handle<JSFunction> function = NewFunctionBoilerplate(name);
function->set_code(*code);
int literals_array_size = number_of_literals;
// If the function contains object, regexp or array literals,
// allocate extra space for a literals array prefix containing the
// object, regexp and array constructor functions.
if (number_of_literals > 0 || contains_array_literal) {
literals_array_size += JSFunction::kLiteralsPrefixSize;
}
Handle<FixedArray> literals =
Factory::NewFixedArray(literals_array_size, TENURED);
function->set_literals(*literals);
ASSERT(!function->has_initial_map());
ASSERT(!function->has_prototype());
return function;
}
Handle<JSFunction> Factory::NewFunctionBoilerplate(Handle<String> name) {
Handle<SharedFunctionInfo> shared = NewSharedFunctionInfo(name);
CALL_HEAP_FUNCTION(Heap::AllocateFunction(Heap::boilerplate_function_map(),
*shared,
Heap::the_hole_value()),
JSFunction);
}
Handle<JSFunction> Factory::NewFunctionWithPrototype(Handle<String> name,
InstanceType type,
int instance_size,
Handle<JSObject> prototype,
Handle<Code> code,
bool force_initial_map) {
// Allocate the function
Handle<JSFunction> function = NewFunction(name, prototype);
function->set_code(*code);
if (force_initial_map ||
type != JS_OBJECT_TYPE ||
instance_size != JSObject::kHeaderSize) {
Handle<Map> initial_map = NewMap(type, instance_size);
function->set_initial_map(*initial_map);
initial_map->set_constructor(*function);
}
// Set function.prototype and give the prototype a constructor
// property that refers to the function.
SetPrototypeProperty(function, prototype);
SetProperty(prototype, Factory::constructor_symbol(), function, DONT_ENUM);
return function;
}
Handle<Code> Factory::NewCode(const CodeDesc& desc, ScopeInfo<>* sinfo,
Code::Flags flags) {
CALL_HEAP_FUNCTION(Heap::CreateCode(desc, sinfo, flags), Code);
}
Handle<Code> Factory::CopyCode(Handle<Code> code) {
CALL_HEAP_FUNCTION(Heap::CopyCode(*code), Code);
}
#define CALL_GC(RETRY) \
do { \
if (!Heap::CollectGarbage(Failure::cast(RETRY)->requested(), \
Failure::cast(RETRY)->allocation_space())) { \
/* TODO(1181417): Fix this. */ \
V8::FatalProcessOutOfMemory("Factory CALL_GC"); \
} \
} while (false)
// Allocate the new array. We cannot use the CALL_HEAP_FUNCTION macro here,
// because the stack-allocated CallbacksDescriptor instance is not GC safe.
Handle<DescriptorArray> Factory::CopyAppendProxyDescriptor(
Handle<DescriptorArray> array,
Handle<String> key,
Handle<Object> value,
PropertyAttributes attributes) {
GC_GREEDY_CHECK();
CallbacksDescriptor desc(*key, *value, attributes);
Object* obj = array->CopyInsert(&desc, REMOVE_TRANSITIONS);
if (obj->IsFailure()) {
if (obj->IsRetryAfterGC()) {
CALL_GC(obj);
CallbacksDescriptor desc(*key, *value, attributes);
obj = array->CopyInsert(&desc, REMOVE_TRANSITIONS);
}
if (obj->IsFailure()) {
// TODO(1181417): Fix this.
V8::FatalProcessOutOfMemory("CopyAppendProxyDescriptor");
}
}
return Handle<DescriptorArray>(DescriptorArray::cast(obj));
}
#undef CALL_GC
Handle<String> Factory::SymbolFromString(Handle<String> value) {
CALL_HEAP_FUNCTION(Heap::LookupSymbol(*value), String);
}
Handle<DescriptorArray> Factory::CopyAppendCallbackDescriptors(
Handle<DescriptorArray> array,
Handle<Object> descriptors) {
v8::NeanderArray callbacks(descriptors);
int nof_callbacks = callbacks.length();
Handle<DescriptorArray> result =
NewDescriptorArray(array->number_of_descriptors() + nof_callbacks);
// Number of descriptors added to the result so far.
int descriptor_count = 0;
// Copy the descriptors from the array.
DescriptorWriter w(*result);
for (DescriptorReader r(*array); !r.eos(); r.advance()) {
w.WriteFrom(&r);
descriptor_count++;
}
// Number of duplicates detected.
int duplicates = 0;
// Fill in new callback descriptors. Process the callbacks from
// back to front so that the last callback with a given name takes
// precedence over previously added callbacks with that name.
for (int i = nof_callbacks - 1; i >= 0; i--) {
Handle<AccessorInfo> entry =
Handle<AccessorInfo>(AccessorInfo::cast(callbacks.get(i)));
// Ensure the key is a symbol before writing into the instance descriptor.
Handle<String> key =
SymbolFromString(Handle<String>(String::cast(entry->name())));
// Check if a descriptor with this name already exists before writing.
if (result->LinearSearch(*key, descriptor_count) ==
DescriptorArray::kNotFound) {
CallbacksDescriptor desc(*key, *entry, entry->property_attributes());
w.Write(&desc);
descriptor_count++;
} else {
duplicates++;
}
}
// If duplicates were detected, allocate a result of the right size
// and transfer the elements.
if (duplicates > 0) {
Handle<DescriptorArray> new_result =
NewDescriptorArray(result->number_of_descriptors() - duplicates);
DescriptorWriter w(*new_result);
DescriptorReader r(*result);
while (!w.eos()) {
w.WriteFrom(&r);
r.advance();
}
result = new_result;
}
// Sort the result before returning.
result->Sort();
return result;
}
Handle<JSObject> Factory::NewJSObject(Handle<JSFunction> constructor,
PretenureFlag pretenure) {
CALL_HEAP_FUNCTION(Heap::AllocateJSObject(*constructor, pretenure), JSObject);
}
Handle<JSObject> Factory::NewJSObjectFromMap(Handle<Map> map) {
CALL_HEAP_FUNCTION(Heap::AllocateJSObjectFromMap(*map, NOT_TENURED),
JSObject);
}
Handle<JSObject> Factory::NewObjectLiteral(int expected_number_of_properties) {
Handle<Map> map = Handle<Map>(Top::object_function()->initial_map());
map = Factory::CopyMap(map);
map->set_instance_descriptors(Heap::empty_descriptor_array());
map->set_unused_property_fields(expected_number_of_properties);
CALL_HEAP_FUNCTION(Heap::AllocateJSObjectFromMap(*map, TENURED),
JSObject);
}
Handle<JSArray> Factory::NewArrayLiteral(int length) {
return NewJSArrayWithElements(NewFixedArray(length), TENURED);
}
Handle<JSArray> Factory::NewJSArray(int length,
PretenureFlag pretenure) {
Handle<JSObject> obj = NewJSObject(Top::array_function(), pretenure);
CALL_HEAP_FUNCTION(Handle<JSArray>::cast(obj)->Initialize(length), JSArray);
}
Handle<JSArray> Factory::NewJSArrayWithElements(Handle<FixedArray> elements,
PretenureFlag pretenure) {
Handle<JSArray> result =
Handle<JSArray>::cast(NewJSObject(Top::array_function(), pretenure));
result->SetContent(*elements);
return result;
}
Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(Handle<String> name) {
CALL_HEAP_FUNCTION(Heap::AllocateSharedFunctionInfo(*name),
SharedFunctionInfo);
}
Handle<Dictionary> Factory::DictionaryAtNumberPut(Handle<Dictionary> dictionary,
uint32_t key,
Handle<Object> value) {
CALL_HEAP_FUNCTION(dictionary->AtNumberPut(key, *value), Dictionary);
}
Handle<JSFunction> Factory::NewFunctionHelper(Handle<String> name,
Handle<Object> prototype) {
Handle<SharedFunctionInfo> function_share = NewSharedFunctionInfo(name);
CALL_HEAP_FUNCTION(Heap::AllocateFunction(*Top::function_map(),
*function_share,
*prototype),
JSFunction);
}
Handle<JSFunction> Factory::NewFunction(Handle<String> name,
Handle<Object> prototype) {
Handle<JSFunction> fun = NewFunctionHelper(name, prototype);
fun->set_context(Top::context()->global_context());
return fun;
}
Handle<Object> Factory::ToObject(Handle<Object> object,
Handle<Context> global_context) {
CALL_HEAP_FUNCTION(object->ToObject(*global_context), Object);
}
Handle<DebugInfo> Factory::NewDebugInfo(Handle<SharedFunctionInfo> shared) {
// Get the original code of the function.
Handle<Code> code(shared->code());
// Create a copy of the code before allocating the debug info object to avoid
// allocation while setting up the debug info object.
Handle<Code> original_code(*Factory::CopyCode(code));
// Allocate initial fixed array for active break points before allocating the
// debug info object to avoid allocation while setting up the debug info
// object.
Handle<FixedArray> break_points(
Factory::NewFixedArray(Debug::kEstimatedNofBreakPointsInFunction));
// Create and set up the debug info object. Debug info contains function, a
// copy of the original code, the executing code and initial fixed array for
// active break points.
Handle<DebugInfo> debug_info =
Handle<DebugInfo>::cast(Factory::NewStruct(DEBUG_INFO_TYPE));
debug_info->set_shared(*shared);
debug_info->set_original_code(*original_code);
debug_info->set_code(*code);
debug_info->set_break_points(*break_points);
// Link debug info to function.
shared->set_debug_info(*debug_info);
return debug_info;
}
Handle<JSObject> Factory::NewArgumentsObject(Handle<Object> callee,
int length) {
CALL_HEAP_FUNCTION(Heap::AllocateArgumentsObject(*callee, length), JSObject);
}
Handle<JSFunction> Factory::CreateApiFunction(
Handle<FunctionTemplateInfo> obj, ApiInstanceType instance_type) {
Handle<Code> code = Handle<Code>(Builtins::builtin(Builtins::HandleApiCall));
int internal_field_count = 0;
if (!obj->instance_template()->IsUndefined()) {
Handle<ObjectTemplateInfo> instance_template =
Handle<ObjectTemplateInfo>(
ObjectTemplateInfo::cast(obj->instance_template()));
internal_field_count =
Smi::cast(instance_template->internal_field_count())->value();
}
int instance_size = kPointerSize * internal_field_count;
InstanceType type = INVALID_TYPE;
switch (instance_type) {
case JavaScriptObject:
type = JS_OBJECT_TYPE;
instance_size += JSObject::kHeaderSize;
break;
case InnerGlobalObject:
type = JS_GLOBAL_OBJECT_TYPE;
instance_size += JSGlobalObject::kSize;
break;
case OuterGlobalObject:
type = JS_GLOBAL_PROXY_TYPE;
instance_size += JSGlobalProxy::kSize;
break;
default:
break;
}
ASSERT(type != INVALID_TYPE);
Handle<JSFunction> result =
Factory::NewFunction(Factory::empty_symbol(), type, instance_size,
code, true);
// Set class name.
Handle<Object> class_name = Handle<Object>(obj->class_name());
if (class_name->IsString()) {
result->shared()->set_instance_class_name(*class_name);
result->shared()->set_name(*class_name);
}
Handle<Map> map = Handle<Map>(result->initial_map());
// Mark as undetectable if needed.
if (obj->undetectable()) {
map->set_is_undetectable();
}
// Mark as hidden for the __proto__ accessor if needed.
if (obj->hidden_prototype()) {
map->set_is_hidden_prototype();
}
// Mark as needs_access_check if needed.
if (obj->needs_access_check()) {
map->set_is_access_check_needed();
}
// Set interceptor information in the map.
if (!obj->named_property_handler()->IsUndefined()) {
map->set_has_named_interceptor();
}
if (!obj->indexed_property_handler()->IsUndefined()) {
map->set_has_indexed_interceptor();
}
// Set instance call-as-function information in the map.
if (!obj->instance_call_handler()->IsUndefined()) {
map->set_has_instance_call_handler();
}
result->shared()->set_function_data(*obj);
result->shared()->DontAdaptArguments();
// Recursively copy parent templates' accessors, 'data' may be modified.
Handle<DescriptorArray> array =
Handle<DescriptorArray>(map->instance_descriptors());
while (true) {
Handle<Object> props = Handle<Object>(obj->property_accessors());
if (!props->IsUndefined()) {
array = Factory::CopyAppendCallbackDescriptors(array, props);
}
Handle<Object> parent = Handle<Object>(obj->parent_template());
if (parent->IsUndefined()) break;
obj = Handle<FunctionTemplateInfo>::cast(parent);
}
if (!array->IsEmpty()) {
map->set_instance_descriptors(*array);
}
return result;
}
Handle<MapCache> Factory::NewMapCache(int at_least_space_for) {
CALL_HEAP_FUNCTION(MapCache::Allocate(at_least_space_for), MapCache);
}
static Object* UpdateMapCacheWith(Context* context,
FixedArray* keys,
Map* map) {
Object* result = MapCache::cast(context->map_cache())->Put(keys, map);
if (!result->IsFailure()) context->set_map_cache(MapCache::cast(result));
return result;
}
Handle<MapCache> Factory::AddToMapCache(Handle<Context> context,
Handle<FixedArray> keys,
Handle<Map> map) {
CALL_HEAP_FUNCTION(UpdateMapCacheWith(*context, *keys, *map), MapCache);
}
Handle<Map> Factory::ObjectLiteralMapFromCache(Handle<Context> context,
Handle<FixedArray> keys) {
if (context->map_cache()->IsUndefined()) {
// Allocate the new map cache for the global context.
Handle<MapCache> new_cache = NewMapCache(24);
context->set_map_cache(*new_cache);
}
// Check to see whether there is a maching element in the cache.
Handle<MapCache> cache =
Handle<MapCache>(MapCache::cast(context->map_cache()));
Handle<Object> result = Handle<Object>(cache->Lookup(*keys));
if (result->IsMap()) return Handle<Map>::cast(result);
// Create a new map and add it to the cache.
Handle<Map> map =
CopyMap(Handle<Map>(context->object_function()->initial_map()));
AddToMapCache(context, keys, map);
return Handle<Map>(map);
}
void Factory::SetRegExpData(Handle<JSRegExp> regexp,
JSRegExp::Type type,
Handle<String> source,
JSRegExp::Flags flags,
Handle<Object> data) {
Handle<FixedArray> store = NewFixedArray(JSRegExp::kDataSize);
store->set(JSRegExp::kTagIndex, Smi::FromInt(type));
store->set(JSRegExp::kSourceIndex, *source);
store->set(JSRegExp::kFlagsIndex, Smi::FromInt(flags.value()));
store->set(JSRegExp::kAtomPatternIndex, *data);
regexp->set_data(*store);
}
void Factory::ConfigureInstance(Handle<FunctionTemplateInfo> desc,
Handle<JSObject> instance,
bool* pending_exception) {
// Configure the instance by adding the properties specified by the
// instance template.
Handle<Object> instance_template = Handle<Object>(desc->instance_template());
if (!instance_template->IsUndefined()) {
Execution::ConfigureInstance(instance,
instance_template,
pending_exception);
} else {
*pending_exception = false;
}
}
} } // namespace v8::internal

View File

@ -1,343 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#ifndef V8_FACTORY_H_
#define V8_FACTORY_H_
#include "heap.h"
namespace v8 { namespace internal {
// Interface for handle based allocation.
class Factory : public AllStatic {
public:
// Allocate a new fixed array.
static Handle<FixedArray> NewFixedArray(
int size,
PretenureFlag pretenure = NOT_TENURED);
static Handle<DescriptorArray> NewDescriptorArray(int number_of_descriptors);
static Handle<String> LookupSymbol(Vector<const char> str);
static Handle<String> LookupAsciiSymbol(const char* str) {
return LookupSymbol(CStrVector(str));
}
// String creation functions. Most of the string creation functions take
// a Heap::PretenureFlag argument to optionally request that they be
// allocated in the old generation. The pretenure flag defaults to
// DONT_TENURE.
//
// Creates a new String object. There are two String encodings: ASCII and
// two byte. One should choose between the three string factory functions
// based on the encoding of the string buffer that the string is
// initialized from.
// - ...FromAscii initializes the string from a buffer that is ASCII
// encoded (it does not check that the buffer is ASCII encoded) and
// the result will be ASCII encoded.
// - ...FromUtf8 initializes the string from a buffer that is UTF-8
// encoded. If the characters are all single-byte characters, the
// result will be ASCII encoded, otherwise it will converted to two
// byte.
// - ...FromTwoByte initializes the string from a buffer that is two
// byte encoded. If the characters are all single-byte characters,
// the result will be converted to ASCII, otherwise it will be left as
// two byte.
//
// ASCII strings are pretenured when used as keys in the SourceCodeCache.
static Handle<String> NewStringFromAscii(
Vector<const char> str,
PretenureFlag pretenure = NOT_TENURED);
// UTF8 strings are pretenured when used for regexp literal patterns and
// flags in the parser.
static Handle<String> NewStringFromUtf8(
Vector<const char> str,
PretenureFlag pretenure = NOT_TENURED);
static Handle<String> NewStringFromTwoByte(Vector<const uc16> str);
// Allocates and partially initializes a TwoByte String. The characters of
// the string are uninitialized. Currently used in regexp code only, where
// they are pretenured.
static Handle<String> NewRawTwoByteString(
int length,
PretenureFlag pretenure = NOT_TENURED);
// Create a new cons string object which consists of a pair of strings.
static Handle<String> NewConsString(Handle<String> first,
Handle<String> second);
// Create a new sliced string object which represents a substring of a
// backing string.
static Handle<String> NewStringSlice(Handle<String> str, int begin, int end);
// Creates a new external String object. There are two String encodings
// in the system: ASCII and two byte. Unlike other String types, it does
// not make sense to have a UTF-8 factory function for external strings,
// because we cannot change the underlying buffer.
static Handle<String> NewExternalStringFromAscii(
ExternalAsciiString::Resource* resource);
static Handle<String> NewExternalStringFromTwoByte(
ExternalTwoByteString::Resource* resource);
// Create a global (but otherwise uninitialized) context.
static Handle<Context> NewGlobalContext();
// Create a function context.
static Handle<Context> NewFunctionContext(int length,
Handle<JSFunction> closure);
// Create a 'with' context.
static Handle<Context> NewWithContext(Handle<Context> previous,
Handle<JSObject> extension);
// Return the Symbol maching the passed in string.
static Handle<String> SymbolFromString(Handle<String> value);
// Allocate a new struct. The struct is pretenured (allocated directly in
// the old generation).
static Handle<Struct> NewStruct(InstanceType type);
static Handle<AccessorInfo> NewAccessorInfo();
static Handle<Script> NewScript(Handle<String> source);
// Proxies are pretenured when allocated by the bootstrapper.
static Handle<Proxy> NewProxy(Address addr,
PretenureFlag pretenure = NOT_TENURED);
// Allocate a new proxy. The proxy is pretenured (allocated directly in
// the old generation).
static Handle<Proxy> NewProxy(const AccessorDescriptor* proxy);
static Handle<ByteArray> NewByteArray(int length);
static Handle<Map> NewMap(InstanceType type, int instance_size);
static Handle<JSObject> NewFunctionPrototype(Handle<JSFunction> function);
static Handle<Map> CopyMap(Handle<Map> map);
static Handle<Map> CopyMapDropTransitions(Handle<Map> map);
static Handle<FixedArray> CopyFixedArray(Handle<FixedArray> array);
// Numbers (eg, literals) are pretenured by the parser.
static Handle<Object> NewNumber(double value,
PretenureFlag pretenure = NOT_TENURED);
static Handle<Object> NewNumberFromInt(int value);
// These objects are used by the api to create env-independent data
// structures in the heap.
static Handle<JSObject> NewNeanderObject();
static Handle<JSObject> NewArgumentsObject(Handle<Object> callee, int length);
// JS objects are pretenured when allocated by the bootstrapper and
// runtime.
static Handle<JSObject> NewJSObject(Handle<JSFunction> constructor,
PretenureFlag pretenure = NOT_TENURED);
// JS objects are pretenured when allocated by the bootstrapper and
// runtime.
static Handle<JSObject> NewJSObjectFromMap(Handle<Map> map);
// Allocate a JS object representing an object literal. The object is
// pretenured (allocated directly in the old generation).
static Handle<JSObject> NewObjectLiteral(int expected_number_of_properties);
// Allocate a JS array representing an array literal. The array is
// pretenured (allocated directly in the old generation).
static Handle<JSArray> NewArrayLiteral(int length);
// JS arrays are pretenured when allocated by the parser.
static Handle<JSArray> NewJSArray(int init_length,
PretenureFlag pretenure = NOT_TENURED);
static Handle<JSArray> NewJSArrayWithElements(
Handle<FixedArray> elements,
PretenureFlag pretenure = NOT_TENURED);
static Handle<JSFunction> NewFunction(Handle<String> name,
Handle<Object> prototype);
static Handle<JSFunction> NewFunction(Handle<Object> super, bool is_global);
static Handle<JSFunction> NewFunctionFromBoilerplate(
Handle<JSFunction> boilerplate,
Handle<Context> context);
static Handle<Code> NewCode(const CodeDesc& desc, ScopeInfo<>* sinfo,
Code::Flags flags);
static Handle<Code> CopyCode(Handle<Code> code);
static Handle<Object> ToObject(Handle<Object> object,
Handle<Context> global_context);
// Interface for creating error objects.
static Handle<Object> NewError(const char* maker, const char* type,
Handle<JSArray> args);
static Handle<Object> NewError(const char* maker, const char* type,
Vector< Handle<Object> > args);
static Handle<Object> NewError(const char* type,
Vector< Handle<Object> > args);
static Handle<Object> NewError(Handle<String> message);
static Handle<Object> NewError(const char* constructor,
Handle<String> message);
static Handle<Object> NewTypeError(const char* type,
Vector< Handle<Object> > args);
static Handle<Object> NewTypeError(Handle<String> message);
static Handle<Object> NewRangeError(const char* type,
Vector< Handle<Object> > args);
static Handle<Object> NewRangeError(Handle<String> message);
static Handle<Object> NewSyntaxError(const char* type, Handle<JSArray> args);
static Handle<Object> NewSyntaxError(Handle<String> message);
static Handle<Object> NewReferenceError(const char* type,
Vector< Handle<Object> > args);
static Handle<Object> NewReferenceError(Handle<String> message);
static Handle<Object> NewEvalError(const char* type,
Vector< Handle<Object> > args);
static Handle<JSFunction> NewFunction(Handle<String> name,
InstanceType type,
int instance_size,
Handle<Code> code,
bool force_initial_map);
static Handle<JSFunction> NewFunctionBoilerplate(Handle<String> name,
int number_of_literals,
bool contains_array_literal,
Handle<Code> code);
static Handle<JSFunction> NewFunctionBoilerplate(Handle<String> name);
static Handle<JSFunction> NewFunction(Handle<Map> function_map,
Handle<SharedFunctionInfo> shared, Handle<Object> prototype);
static Handle<JSFunction> NewFunctionWithPrototype(Handle<String> name,
InstanceType type,
int instance_size,
Handle<JSObject> prototype,
Handle<Code> code,
bool force_initial_map);
static Handle<DescriptorArray> CopyAppendProxyDescriptor(
Handle<DescriptorArray> array,
Handle<String> key,
Handle<Object> value,
PropertyAttributes attributes);
enum ApiInstanceType {
JavaScriptObject,
InnerGlobalObject,
OuterGlobalObject
};
static Handle<JSFunction> CreateApiFunction(
Handle<FunctionTemplateInfo> data,
ApiInstanceType type = JavaScriptObject);
static Handle<JSFunction> InstallMembers(Handle<JSFunction> function);
// Installs interceptors on the instance. 'desc' is a function template,
// and instance is an object instance created by the function of this
// function tempalte.
static void ConfigureInstance(Handle<FunctionTemplateInfo> desc,
Handle<JSObject> instance,
bool* pending_exception);
#define ROOT_ACCESSOR(type, name) \
static Handle<type> name() { return Handle<type>(&Heap::name##_); }
ROOT_LIST(ROOT_ACCESSOR)
#undef ROOT_ACCESSOR_ACCESSOR
#define SYMBOL_ACCESSOR(name, str) \
static Handle<String> name() { return Handle<String>(&Heap::name##_); }
SYMBOL_LIST(SYMBOL_ACCESSOR)
#undef SYMBOL_ACCESSOR
static Handle<SharedFunctionInfo> NewSharedFunctionInfo(Handle<String> name);
static Handle<Dictionary> DictionaryAtNumberPut(Handle<Dictionary>,
uint32_t key,
Handle<Object> value);
static Handle<DebugInfo> NewDebugInfo(Handle<SharedFunctionInfo> shared);
// Return a map using the map cache in the global context.
// The key the an ordered set of property names.
static Handle<Map> ObjectLiteralMapFromCache(Handle<Context> context,
Handle<FixedArray> keys);
// Creates a new FixedArray that holds the data associated with the
// regexp and stores it in the regexp.
static void SetRegExpData(Handle<JSRegExp> regexp,
JSRegExp::Type type,
Handle<String> source,
JSRegExp::Flags flags,
Handle<Object> data);
private:
static Handle<JSFunction> NewFunctionHelper(Handle<String> name,
Handle<Object> prototype);
static Handle<DescriptorArray> CopyAppendCallbackDescriptors(
Handle<DescriptorArray> array,
Handle<Object> descriptors);
static Handle<JSFunction> BaseNewFunctionFromBoilerplate(
Handle<JSFunction> boilerplate,
Handle<Map> function_map);
// Create a new map cache.
static Handle<MapCache> NewMapCache(int at_least_space_for);
// Update the map cache in the global context with (keys, map)
static Handle<MapCache> AddToMapCache(Handle<Context> context,
Handle<FixedArray> keys,
Handle<Map> map);
};
} } // namespace v8::internal
#endif // V8_FACTORY_H_

View File

@ -1,323 +0,0 @@
// Copyright 2008 the V8 project 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.
// This file defines all of the flags. It is separated into different section,
// for Debug, Release, Logging and Profiling, etc. To add a new flag, find the
// correct section, and use one of the DEFINE_ macros, without a trailing ';'.
//
// This include does not have a guard, because it is a template-style include,
// which can be included multiple times in different modes. It expects to have
// a mode defined before it's included. The modes are FLAG_MODE_... below:
// We want to declare the names of the variables for the header file. Normally
// this will just be an extern declaration, but for a readonly flag we let the
// compiler make better optimizations by giving it the value.
#if defined(FLAG_MODE_DECLARE)
#define FLAG_FULL(ftype, ctype, nam, def, cmt) \
extern ctype FLAG_##nam;
#define FLAG_READONLY(ftype, ctype, nam, def, cmt) \
static ctype const FLAG_##nam = def;
// We want to supply the actual storage and value for the flag variable in the
// .cc file. We only do this for writable flags.
#elif defined(FLAG_MODE_DEFINE)
#define FLAG_FULL(ftype, ctype, nam, def, cmt) \
ctype FLAG_##nam = def;
#define FLAG_READONLY(ftype, ctype, nam, def, cmt)
// We need to define all of our default values so that the Flag structure can
// access them by pointer. These are just used internally inside of one .cc,
// for MODE_META, so there is no impact on the flags interface.
#elif defined(FLAG_MODE_DEFINE_DEFAULTS)
#define FLAG_FULL(ftype, ctype, nam, def, cmt) \
static ctype const FLAGDEFAULT_##nam = def;
#define FLAG_READONLY(ftype, ctype, nam, def, cmt)
// We want to write entries into our meta data table, for internal parsing and
// printing / etc in the flag parser code. We only do this for writable flags.
#elif defined(FLAG_MODE_META)
#define FLAG_FULL(ftype, ctype, nam, def, cmt) \
{ Flag::TYPE_##ftype, #nam, &FLAG_##nam, &FLAGDEFAULT_##nam, cmt },
#define FLAG_READONLY(ftype, ctype, nam, def, cmt)
#else
#error No mode supplied when including flags.defs
#endif
#define DEFINE_bool(nam, def, cmt) FLAG(BOOL, bool, nam, def, cmt)
#define DEFINE_int(nam, def, cmt) FLAG(INT, int, nam, def, cmt)
#define DEFINE_float(nam, def, cmt) FLAG(FLOAT, double, nam, def, cmt)
#define DEFINE_string(nam, def, cmt) FLAG(STRING, const char*, nam, def, cmt)
//
// Flags in all modes.
//
#define FLAG FLAG_FULL
// assembler-ia32.cc / assembler-arm.cc
DEFINE_bool(debug_code, false,
"generate extra code (comments, assertions) for debugging")
DEFINE_bool(emit_branch_hints, false, "emit branch hints")
DEFINE_bool(push_pop_elimination, true,
"eliminate redundant push/pops in assembly code")
DEFINE_bool(print_push_pop_elimination, false,
"print elimination of redundant push/pops in assembly code")
// bootstrapper.cc
DEFINE_string(expose_natives_as, NULL, "expose natives in global object")
DEFINE_string(expose_debug_as, NULL, "expose debug in global object")
DEFINE_string(natives_file, NULL, "alternative natives file")
DEFINE_bool(expose_gc, false, "expose gc extension")
// builtins-ia32.cc
DEFINE_bool(inline_new, true, "use fast inline allocation")
// checks.cc
DEFINE_bool(stack_trace_on_abort, true,
"print a stack trace if an assertion failure occurs")
// codegen-ia32.cc / codegen-arm.cc
DEFINE_bool(trace, false, "trace function calls")
DEFINE_bool(defer_negation, true, "defer negation operation")
DEFINE_bool(check_stack, true,
"check stack for overflow, interrupt, breakpoint")
// codegen.cc
DEFINE_bool(lazy, true, "use lazy compilation")
DEFINE_bool(debug_info, true, "add debug information to compiled functions")
// compiler.cc
DEFINE_bool(strict, false, "strict error checking")
DEFINE_int(min_preparse_length, 1024,
"Minimum length for automatic enable preparsing")
// debug.cc
DEFINE_bool(remote_debugging, false, "enable remote debugging")
DEFINE_bool(trace_debug_json, false, "trace debugging JSON request/response")
// execution.cc
DEFINE_bool(call_regexp, false, "allow calls to RegExp objects")
// frames.cc
DEFINE_int(max_stack_trace_source_length, 300,
"maximum length of function source code printed in a stack trace.")
// heap.cc
DEFINE_int(new_space_size, 0, "size of (each semispace in) the new generation")
DEFINE_int(old_space_size, 0, "size of the old generation")
DEFINE_bool(gc_global, false, "always perform global GCs")
DEFINE_int(gc_interval, -1, "garbage collect after <n> allocations")
DEFINE_bool(trace_gc, false,
"print one trace line following each garbage collection")
// ic.cc
DEFINE_bool(use_ic, true, "use inline caching")
// macro-assembler-ia32.cc
DEFINE_bool(native_code_counters, false,
"generate extra code for manipulating stats counters")
// mark-compact.cc
DEFINE_bool(always_compact, false, "Perform compaction on every full GC")
DEFINE_bool(never_compact, false,
"Never perform compaction on full GC - testing only")
DEFINE_bool(cleanup_ics_at_gc, true,
"Flush inline caches prior to mark compact collection.")
DEFINE_bool(cleanup_caches_in_maps_at_gc, true,
"Flush code caches in maps during mark compact cycle.")
DEFINE_bool(canonicalize_object_literal_maps, true,
"Canonicalize maps for object literals.")
// mksnapshot.cc
DEFINE_bool(h, false, "print this message")
// parser.cc
DEFINE_bool(allow_natives_syntax, false, "allow natives syntax")
// simulator-arm.cc
DEFINE_bool(trace_sim, false, "trace simulator execution")
DEFINE_int(stop_sim_at, 0, "Simulator stop after x number of instructions")
// top.cc
DEFINE_bool(trace_exception, false,
"print stack trace when throwing exceptions")
DEFINE_bool(preallocate_message_memory, false,
"preallocate some memory to build stack traces.")
// usage-analyzer.cc
DEFINE_bool(usage_computation, true, "compute variable usage counts")
// v8.cc
DEFINE_bool(preemption, false,
"activate a 100ms timer that switches between V8 threads")
// Testing flags test/cctest/test-{flags,api,serialization}.cc
DEFINE_bool(testing_bool_flag, true, "testing_bool_flag")
DEFINE_int(testing_int_flag, 13, "testing_int_flag")
DEFINE_float(testing_float_flag, 2.5, "float-flag")
DEFINE_string(testing_string_flag, "Hello, world!", "string-flag")
DEFINE_int(testing_prng_seed, 42, "Seed used for threading test randomness")
#ifdef WIN32
DEFINE_string(testing_serialization_file, "C:\\Windows\\Temp\\serdes",
"file in which to testing_serialize heap")
#else
DEFINE_string(testing_serialization_file, "/tmp/serdes",
"file in which to serialize heap")
#endif
//
// Dev shell flags
//
DEFINE_bool(dump_counters, false, "Dump counters on exit")
//
// Debug only flags
//
#undef FLAG
#ifdef DEBUG
#define FLAG FLAG_FULL
#else
#define FLAG FLAG_READONLY
#endif
// checks.cc
DEFINE_bool(enable_slow_asserts, false,
"enable asserts that are slow to execute")
// code-stubs.cc
DEFINE_bool(print_code_stubs, false, "print code stubs")
// codegen-ia32.cc / codegen-arm.cc
DEFINE_bool(trace_codegen, false,
"print name of functions for which code is generated")
DEFINE_bool(print_builtin_code, false, "print generated code for builtins")
DEFINE_bool(print_source, false, "pretty print source code")
DEFINE_bool(print_builtin_source, false,
"pretty print source code for builtins")
DEFINE_bool(print_ast, false, "print source AST")
DEFINE_bool(print_builtin_ast, false, "print source AST for builtins")
DEFINE_bool(trace_calls, false, "trace calls")
DEFINE_bool(trace_builtin_calls, false, "trace builtins calls")
DEFINE_string(stop_at, "", "function name where to insert a breakpoint")
// compiler.cc
DEFINE_bool(print_builtin_scopes, false, "print scopes for builtins")
DEFINE_bool(print_scopes, false, "print scopes")
// contexts.cc
DEFINE_bool(trace_contexts, false, "trace contexts operations")
// heap.cc
DEFINE_bool(gc_greedy, false, "perform GC prior to some allocations")
DEFINE_bool(gc_verbose, false, "print stuff during garbage collection")
DEFINE_bool(heap_stats, false, "report heap statistics before and after GC")
DEFINE_bool(code_stats, false, "report code statistics after GC")
DEFINE_bool(verify_heap, false, "verify heap pointers before and after GC")
DEFINE_bool(print_handles, false, "report handles after GC")
DEFINE_bool(print_global_handles, false, "report global handles after GC")
DEFINE_bool(print_rset, false, "print remembered sets before GC")
// ic.cc
DEFINE_bool(trace_ic, false, "trace inline cache state transitions")
// objects.cc
DEFINE_bool(trace_normalization,
false,
"prints when objects are turned into dictionaries.")
// runtime.cc
DEFINE_bool(trace_lazy, false, "trace lazy compilation")
// serialize.cc
DEFINE_bool(debug_serialization, false,
"write debug information into the snapshot.")
// spaces.cc
DEFINE_bool(collect_heap_spill_statistics, false,
"report heap spill statistics along with heap_stats "
"(requires heap_stats)")
DEFINE_bool(trace_regexps, false, "trace regexp execution")
//
// Logging and profiling only flags
//
#undef FLAG
#ifdef ENABLE_LOGGING_AND_PROFILING
#define FLAG FLAG_FULL
#else
#define FLAG FLAG_READONLY
#endif
// log.cc
DEFINE_bool(log, false,
"Minimal logging (no API, code, GC, suspect, or handles samples).")
DEFINE_bool(log_all, false, "Log all events to the log file.")
DEFINE_bool(log_api, false, "Log API events to the log file.")
DEFINE_bool(log_code, false,
"Log code events to the log file without profiling.")
DEFINE_bool(log_gc, false,
"Log heap samples on garbage collection for the hp2ps tool.")
DEFINE_bool(log_handles, false, "Log global handle events.")
DEFINE_bool(log_state_changes, false, "Log state changes.")
DEFINE_bool(log_suspect, false, "Log suspect operations.")
DEFINE_bool(prof, false,
"Log statistical profiling information (implies --log-code).")
DEFINE_bool(log_regexp, false, "Log regular expression execution.")
DEFINE_bool(sliding_state_window, false,
"Update sliding state window counters.")
DEFINE_string(logfile, "v8.log", "Specify the name of the log file.")
//
// Disassembler only flags
//
#undef FLAG
#ifdef ENABLE_DISASSEMBLER
#define FLAG FLAG_FULL
#else
#define FLAG FLAG_READONLY
#endif
// codegen-ia32.cc / codegen-arm.cc
DEFINE_bool(print_code, false, "print generated code")
// Cleanup...
#undef FLAG_FULL
#undef FLAG_READONLY
#undef FLAG
#undef DEFINE_bool
#undef DEFINE_int
#undef DEFINE_string
#undef FLAG_MODE_DECLARE
#undef FLAG_MODE_DEFINE
#undef FLAG_MODE_DEFINE_DEFAULTS
#undef FLAG_MODE_META

View File

@ -1,459 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#include <ctype.h>
#include <stdlib.h>
#include "v8.h"
#include "platform.h"
namespace v8 { namespace internal {
// Define all of our flags.
#define FLAG_MODE_DEFINE
#include "flag-definitions.h"
// Define all of our flags default values.
#define FLAG_MODE_DEFINE_DEFAULTS
#include "flag-definitions.h"
namespace {
// This structure represents a single entry in the flag system, with a pointer
// to the actual flag, default value, comment, etc. This is designed to be POD
// initialized as to avoid requiring static constructors.
struct Flag {
enum FlagType { TYPE_BOOL, TYPE_INT, TYPE_FLOAT, TYPE_STRING };
FlagType type_; // What type of flag, bool, int, or string.
const char* name_; // Name of the flag, ex "my_flag".
void* valptr_; // Pointer to the global flag variable.
const void* defptr_; // Pointer to the default value.
const char* cmt_; // A comment about the flags purpose.
FlagType type() const { return type_; }
const char* name() const { return name_; }
const char* comment() const { return cmt_; }
bool* bool_variable() const {
ASSERT(type_ == TYPE_BOOL);
return reinterpret_cast<bool*>(valptr_);
}
int* int_variable() const {
ASSERT(type_ == TYPE_INT);
return reinterpret_cast<int*>(valptr_);
}
double* float_variable() const {
ASSERT(type_ == TYPE_FLOAT);
return reinterpret_cast<double*>(valptr_);
}
const char** string_variable() const {
ASSERT(type_ == TYPE_STRING);
return reinterpret_cast<const char**>(valptr_);
}
bool bool_default() const {
ASSERT(type_ == TYPE_BOOL);
return *reinterpret_cast<const bool*>(defptr_);
}
int int_default() const {
ASSERT(type_ == TYPE_INT);
return *reinterpret_cast<const int*>(defptr_);
}
double float_default() const {
ASSERT(type_ == TYPE_FLOAT);
return *reinterpret_cast<const double*>(defptr_);
}
const char* string_default() const {
ASSERT(type_ == TYPE_STRING);
return *reinterpret_cast<const char* const *>(defptr_);
}
// Compare this flag's current value against the default.
bool IsDefault() const {
switch (type_) {
case TYPE_BOOL:
return *bool_variable() == bool_default();
case TYPE_INT:
return *int_variable() == int_default();
case TYPE_FLOAT:
return *float_variable() == float_default();
case TYPE_STRING:
const char* str1 = *string_variable();
const char* str2 = string_default();
if (str2 == NULL) return str1 == NULL;
if (str1 == NULL) return str2 == NULL;
return strcmp(str1, str2) == 0;
}
UNREACHABLE();
return true;
}
// Set a flag back to it's default value.
void Reset() {
switch (type_) {
case TYPE_BOOL:
*bool_variable() = bool_default();
break;
case TYPE_INT:
*int_variable() = int_default();
break;
case TYPE_FLOAT:
*float_variable() = float_default();
break;
case TYPE_STRING:
*string_variable() = string_default();
break;
}
}
};
Flag flags[] = {
#define FLAG_MODE_META
#include "flag-definitions.h"
};
const size_t num_flags = sizeof(flags) / sizeof(*flags);
} // namespace
static const char* Type2String(Flag::FlagType type) {
switch (type) {
case Flag::TYPE_BOOL: return "bool";
case Flag::TYPE_INT: return "int";
case Flag::TYPE_FLOAT: return "float";
case Flag::TYPE_STRING: return "string";
}
UNREACHABLE();
return NULL;
}
static char* ToString(Flag* flag) {
Vector<char> value;
switch (flag->type()) {
case Flag::TYPE_BOOL:
value = Vector<char>::New(6);
OS::SNPrintF(value, "%s", (*flag->bool_variable() ? "true" : "false"));
break;
case Flag::TYPE_INT:
value = Vector<char>::New(12);
OS::SNPrintF(value, "%d", *flag->int_variable());
break;
case Flag::TYPE_FLOAT:
value = Vector<char>::New(20);
OS::SNPrintF(value, "%f", *flag->float_variable());
break;
case Flag::TYPE_STRING:
const char* str = *flag->string_variable();
if (str) {
int length = strlen(str) + 1;
value = Vector<char>::New(length);
OS::SNPrintF(value, "%s", str);
} else {
value = Vector<char>::New(5);
OS::SNPrintF(value, "NULL");
}
break;
}
ASSERT(!value.is_empty());
return value.start();
}
// static
List<char *>* FlagList::argv() {
List<char *>* args = new List<char*>(8);
for (size_t i = 0; i < num_flags; ++i) {
Flag* f = &flags[i];
if (!f->IsDefault()) {
Vector<char> cmdline_flag;
if (f->type() != Flag::TYPE_BOOL || *(f->bool_variable())) {
int length = strlen(f->name()) + 2 + 1;
cmdline_flag = Vector<char>::New(length);
OS::SNPrintF(cmdline_flag, "--%s", f->name());
} else {
int length = strlen(f->name()) + 4 + 1;
cmdline_flag = Vector<char>::New(length);
OS::SNPrintF(cmdline_flag, "--no%s", f->name());
}
args->Add(cmdline_flag.start());
if (f->type() != Flag::TYPE_BOOL) {
args->Add(ToString(f));
}
}
}
return args;
}
// Helper function to parse flags: Takes an argument arg and splits it into
// a flag name and flag value (or NULL if they are missing). is_bool is set
// if the arg started with "-no" or "--no". The buffer may be used to NUL-
// terminate the name, it must be large enough to hold any possible name.
static void SplitArgument(const char* arg,
char* buffer,
int buffer_size,
const char** name,
const char** value,
bool* is_bool) {
*name = NULL;
*value = NULL;
*is_bool = false;
if (*arg == '-') {
// find the begin of the flag name
arg++; // remove 1st '-'
if (*arg == '-')
arg++; // remove 2nd '-'
if (arg[0] == 'n' && arg[1] == 'o') {
arg += 2; // remove "no"
*is_bool = true;
}
*name = arg;
// find the end of the flag name
while (*arg != '\0' && *arg != '=')
arg++;
// get the value if any
if (*arg == '=') {
// make a copy so we can NUL-terminate flag name
int n = arg - *name;
CHECK(n < buffer_size); // buffer is too small
memcpy(buffer, *name, n);
buffer[n] = '\0';
*name = buffer;
// get the value
*value = arg + 1;
}
}
}
inline char NormalizeChar(char ch) {
return ch == '_' ? '-' : ch;
}
static bool EqualNames(const char* a, const char* b) {
for (int i = 0; NormalizeChar(a[i]) == NormalizeChar(b[i]); i++) {
if (a[i] == '\0') {
return true;
}
}
return false;
}
static Flag* FindFlag(const char* name) {
for (size_t i = 0; i < num_flags; ++i) {
if (EqualNames(name, flags[i].name()))
return &flags[i];
}
return NULL;
}
// static
int FlagList::SetFlagsFromCommandLine(int* argc,
char** argv,
bool remove_flags) {
// parse arguments
for (int i = 1; i < *argc;) {
int j = i; // j > 0
const char* arg = argv[i++];
// split arg into flag components
char buffer[1*KB];
const char* name;
const char* value;
bool is_bool;
SplitArgument(arg, buffer, sizeof buffer, &name, &value, &is_bool);
if (name != NULL) {
// lookup the flag
Flag* flag = FindFlag(name);
if (flag == NULL) {
if (remove_flags) {
// We don't recognize this flag but since we're removing
// the flags we recognize we assume that the remaining flags
// will be processed somewhere else so this flag might make
// sense there.
continue;
} else {
fprintf(stderr, "Error: unrecognized flag %s\n", arg);
return j;
}
}
// if we still need a flag value, use the next argument if available
if (flag->type() != Flag::TYPE_BOOL && value == NULL) {
if (i < *argc) {
value = argv[i++];
} else {
fprintf(stderr, "Error: missing value for flag %s of type %s\n",
arg, Type2String(flag->type()));
return j;
}
}
// set the flag
char* endp = const_cast<char*>(""); // *endp is only read
switch (flag->type()) {
case Flag::TYPE_BOOL:
*flag->bool_variable() = !is_bool;
break;
case Flag::TYPE_INT:
*flag->int_variable() = strtol(value, &endp, 10); // NOLINT
break;
case Flag::TYPE_FLOAT:
*flag->float_variable() = strtod(value, &endp);
break;
case Flag::TYPE_STRING:
*flag->string_variable() = value;
break;
}
// handle errors
if ((flag->type() == Flag::TYPE_BOOL && value != NULL) ||
(flag->type() != Flag::TYPE_BOOL && is_bool) ||
*endp != '\0') {
fprintf(stderr, "Error: illegal value for flag %s of type %s\n",
arg, Type2String(flag->type()));
return j;
}
// remove the flag & value from the command
if (remove_flags)
while (j < i)
argv[j++] = NULL;
}
}
// shrink the argument list
if (remove_flags) {
int j = 1;
for (int i = 1; i < *argc; i++) {
if (argv[i] != NULL)
argv[j++] = argv[i];
}
*argc = j;
}
// parsed all flags successfully
return 0;
}
static char* SkipWhiteSpace(char* p) {
while (*p != '\0' && isspace(*p) != 0) p++;
return p;
}
static char* SkipBlackSpace(char* p) {
while (*p != '\0' && isspace(*p) == 0) p++;
return p;
}
// static
int FlagList::SetFlagsFromString(const char* str, int len) {
// make a 0-terminated copy of str
char* copy0 = NewArray<char>(len + 1);
memcpy(copy0, str, len);
copy0[len] = '\0';
// strip leading white space
char* copy = SkipWhiteSpace(copy0);
// count the number of 'arguments'
int argc = 1; // be compatible with SetFlagsFromCommandLine()
for (char* p = copy; *p != '\0'; argc++) {
p = SkipBlackSpace(p);
p = SkipWhiteSpace(p);
}
// allocate argument array
char** argv = NewArray<char*>(argc);
// split the flags string into arguments
argc = 1; // be compatible with SetFlagsFromCommandLine()
for (char* p = copy; *p != '\0'; argc++) {
argv[argc] = p;
p = SkipBlackSpace(p);
if (*p != '\0') *p++ = '\0'; // 0-terminate argument
p = SkipWhiteSpace(p);
}
// set the flags
int result = SetFlagsFromCommandLine(&argc, argv, false);
// cleanup
DeleteArray(argv);
// don't delete copy0 since the substrings
// may be pointed to by FLAG variables!
// (this is a memory leak, but it's minor since this
// code is only used for debugging, or perhaps once
// during initialization).
return result;
}
// static
void FlagList::ResetAllFlags() {
for (size_t i = 0; i < num_flags; ++i) {
flags[i].Reset();
}
}
// static
void FlagList::PrintHelp() {
for (size_t i = 0; i < num_flags; ++i) {
Flag* f = &flags[i];
char* value = ToString(f);
printf(" --%s (%s) type: %s default: %s\n",
f->name(), f->comment(), Type2String(f->type()), value);
DeleteArray(value);
}
}
} } // namespace v8::internal

View File

@ -1,78 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#ifndef V8_FLAGS_H_
#define V8_FLAGS_H_
#include "checks.h"
namespace v8 { namespace internal {
// Declare all of our flags.
#define FLAG_MODE_DECLARE
#include "flag-definitions.h"
// The global list of all flags.
class FlagList {
public:
// The list of all flags with a value different from the default
// and their values. The format of the list is like the format of the
// argv array passed to the main function, e.g.
// ("--prof", "--log-file", "v8.prof", "--nolazy").
//
// The caller is responsible for disposing the list.
static List<char *>* argv();
// Set the flag values by parsing the command line. If remove_flags is
// set, the flags and associated values are removed from (argc,
// argv). Returns 0 if no error occurred. Otherwise, returns the argv
// index > 0 for the argument where an error occurred. In that case,
// (argc, argv) will remain unchanged indepdendent of the remove_flags
// value, and no assumptions about flag settings should be made.
//
// The following syntax for flags is accepted (both '-' and '--' are ok):
//
// --flag (bool flags only)
// --noflag (bool flags only)
// --flag=value (non-bool flags only, no spaces around '=')
// --flag value (non-bool flags only)
static int SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags);
// Set the flag values by parsing the string str. Splits string into argc
// substrings argv[], each of which consisting of non-white-space chars,
// and then calls SetFlagsFromCommandLine() and returns its result.
static int SetFlagsFromString(const char* str, int len);
// Reset all flags to their default value.
static void ResetAllFlags();
// Print help to stdout with flags, types, and default values.
static void PrintHelp();
};
} } // namespace v8::internal
#endif // V8_FLAGS_H_

View File

@ -1,123 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#include "v8.h"
#include "frames-inl.h"
#include "assembler-arm-inl.h"
namespace v8 { namespace internal {
StackFrame::Type StackFrame::ComputeType(State* state) {
ASSERT(state->fp != NULL);
if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) {
return ARGUMENTS_ADAPTOR;
}
// The marker and function offsets overlap. If the marker isn't a
// smi then the frame is a JavaScript frame -- and the marker is
// really the function.
const int offset = StandardFrameConstants::kMarkerOffset;
Object* marker = Memory::Object_at(state->fp + offset);
if (!marker->IsSmi()) return JAVA_SCRIPT;
return static_cast<StackFrame::Type>(Smi::cast(marker)->value());
}
StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) {
if (fp == 0) return NONE;
// Compute frame type and stack pointer.
Address sp = fp + ExitFrameConstants::kSPDisplacement;
Type type;
if (Memory::Address_at(fp + ExitFrameConstants::kDebugMarkOffset) != 0) {
type = EXIT_DEBUG;
sp -= kNumJSCallerSaved * kPointerSize;
} else {
type = EXIT;
}
// Fill in the state.
state->sp = sp;
state->fp = fp;
state->pc_address = reinterpret_cast<Address*>(sp - 1 * kPointerSize);
return type;
}
void ExitFrame::Iterate(ObjectVisitor* v) const {
// Do nothing
}
int JavaScriptFrame::GetProvidedParametersCount() const {
return ComputeParametersCount();
}
Address JavaScriptFrame::GetCallerStackPointer() const {
int arguments;
if (Heap::gc_state() != Heap::NOT_IN_GC) {
// The arguments for cooked frames are traversed as if they were
// expression stack elements of the calling frame. The reason for
// this rather strange decision is that we cannot access the
// function during mark-compact GCs when the stack is cooked.
// In fact accessing heap objects (like function->shared() below)
// at all during GC is problematic.
arguments = 0;
} else {
// Compute the number of arguments by getting the number of formal
// parameters of the function. We must remember to take the
// receiver into account (+1).
JSFunction* function = JSFunction::cast(this->function());
arguments = function->shared()->formal_parameter_count() + 1;
}
const int offset = StandardFrameConstants::kCallerSPOffset;
return fp() + offset + (arguments * kPointerSize);
}
Address ArgumentsAdaptorFrame::GetCallerStackPointer() const {
const int arguments = Smi::cast(GetExpression(0))->value();
const int offset = StandardFrameConstants::kCallerSPOffset;
return fp() + offset + (arguments + 1) * kPointerSize;
}
Address InternalFrame::GetCallerStackPointer() const {
// Internal frames have no arguments. The stack pointer of the
// caller is at a fixed offset from the frame pointer.
return fp() + StandardFrameConstants::kCallerSPOffset;
}
Code* JavaScriptFrame::FindCode() const {
JSFunction* function = JSFunction::cast(this->function());
return function->shared()->code();
}
} } // namespace v8::internal

View File

@ -1,381 +0,0 @@
// Copyright 2006-2008 the V8 project 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.
#ifndef V8_FRAMES_ARM_H_
#define V8_FRAMES_ARM_H_
namespace v8 { namespace internal {
// The ARM ABI does not specify the usage of register r9, which may be reserved
// as the static base or thread register on some platforms, in which case we
// leave it alone. Adjust the value of kR9Available accordingly:
static const int kR9Available = 1; // 1 if available to us, 0 if reserved
// Register list in load/store instructions
// Note that the bit values must match those used in actual instruction encoding
static const int kNumRegs = 16;
// Caller-saved/arguments registers
static const RegList kJSCallerSaved =
1 << 0 | // r0 a1
1 << 1 | // r1 a2
1 << 2 | // r2 a3
1 << 3; // r3 a4
static const int kNumJSCallerSaved = 4;
typedef Object* JSCallerSavedBuffer[kNumJSCallerSaved];
// Return the code of the n-th caller-saved register available to JavaScript
// e.g. JSCallerSavedReg(0) returns r0.code() == 0
int JSCallerSavedCode(int n);
// Callee-saved registers preserved when switching from C to JavaScript
static const RegList kCalleeSaved =
1 << 4 | // r4 v1
1 << 5 | // r5 v2
1 << 6 | // r6 v3
1 << 7 | // r7 v4
1 << 8 | // r8 v5 (cp in JavaScript code)
kR9Available
<< 9 | // r9 v6
1 << 10 | // r10 v7 (pp in JavaScript code)
1 << 11; // r11 v8 (fp in JavaScript code)
static const int kNumCalleeSaved = 7 + kR9Available;
// ----------------------------------------------------
class StackHandlerConstants : public AllStatic {
public:
// TODO(1233780): Get rid of the code slot in stack handlers.
static const int kCodeOffset = 0 * kPointerSize;
static const int kNextOffset = 1 * kPointerSize;
static const int kStateOffset = 2 * kPointerSize;
static const int kPPOffset = 3 * kPointerSize;
static const int kFPOffset = 4 * kPointerSize;
static const int kPCOffset = 5 * kPointerSize;
static const int kAddressDisplacement = -1 * kPointerSize;
static const int kSize = kPCOffset + kPointerSize;
};
class EntryFrameConstants : public AllStatic {
public:
static const int kCallerFPOffset = -3 * kPointerSize;
};
class ExitFrameConstants : public AllStatic {
public:
// Exit frames have a debug marker on the stack.
static const int kSPDisplacement = -1 * kPointerSize;
// The debug marker is just above the frame pointer.
static const int kDebugMarkOffset = -1 * kPointerSize;
static const int kSavedRegistersOffset = 0 * kPointerSize;
// Let the parameters pointer for exit frames point just below the
// frame structure on the stack.
static const int kPPDisplacement = 3 * kPointerSize;
// The caller fields are below the frame pointer on the stack.
static const int kCallerFPOffset = +0 * kPointerSize;
static const int kCallerPPOffset = +1 * kPointerSize;
static const int kCallerPCOffset = +2 * kPointerSize;
};
class StandardFrameConstants : public AllStatic {
public:
static const int kExpressionsOffset = -3 * kPointerSize;
static const int kMarkerOffset = -2 * kPointerSize;
static const int kContextOffset = -1 * kPointerSize;
static const int kCallerFPOffset = 0 * kPointerSize;
static const int kCallerPCOffset = +1 * kPointerSize;
static const int kCallerSPOffset = +2 * kPointerSize;
};
class JavaScriptFrameConstants : public AllStatic {
public:
// FP-relative.
static const int kLocal0Offset = StandardFrameConstants::kExpressionsOffset;
static const int kSavedRegistersOffset = +2 * kPointerSize;
static const int kFunctionOffset = StandardFrameConstants::kMarkerOffset;
// PP-relative.
static const int kParam0Offset = -2 * kPointerSize;
static const int kReceiverOffset = -1 * kPointerSize;
};
class ArgumentsAdaptorFrameConstants : public AllStatic {
public:
static const int kLengthOffset = StandardFrameConstants::kExpressionsOffset;
};
class InternalFrameConstants : public AllStatic {
public:
static const int kCodeOffset = StandardFrameConstants::kExpressionsOffset;
};
inline Object* JavaScriptFrame::function() const {
const int offset = JavaScriptFrameConstants::kFunctionOffset;
Object* result = Memory::Object_at(fp() + offset);
ASSERT(result->IsJSFunction());
return result;
}
// ----------------------------------------------------
// lower | Stack |
// addresses | ^ |
// | | |
// | |
// | JS frame |
// | |
// | |
// ----------- +=============+ <--- sp (stack pointer)
// | function |
// +-------------+
// +-------------+
// | |
// | expressions |
// | |
// +-------------+
// | |
// a | locals |
// c | |
// t +- - - - - - -+ <---
// i -4 | local0 | ^
// v +-------------+ |
// a -3 | code | |
// t +-------------+ | kLocal0Offset
// i -2 | context | |
// o +-------------+ |
// n -1 | args_length | v
// +-------------+ <--- fp (frame pointer)
// 0 | caller_pp |
// f +-------------+
// r 1 | caller_fp |
// a +-------------+
// m 2 | sp_on_exit | (pp if return, caller_sp if no return)
// e +-------------+
// 3 | caller_pc |
// +-------------+ <--- caller_sp (incl. parameters)
// | |
// | parameters |
// | |
// +- - - - - - -+ <---
// -2 | parameter0 | ^
// +-------------+ | kParam0Offset
// -1 | receiver | v
// ----------- +=============+ <--- pp (parameter pointer, r10)
// 0 | function |
// +-------------+
// | |
// |caller-saved | (must be valid JS values, traversed during GC)
// | regs |
// | |
// +-------------+
// | |
// | caller |
// higher | expressions |
// addresses | |
// | |
// | JS frame |
// Handler frames (part of expressions of JS frames):
// lower | Stack |
// addresses | ^ |
// | | |
// | |
// h | expressions |
// a | |
// n +-------------+
// d -1 | code |
// l +-------------+ <--- handler sp
// e 0 | next_sp | link to next handler (next handler's sp)
// r +-------------+
// 1 | state |
// f +-------------+
// r 2 | pp |
// a +-------------+
// m 3 | fp |
// e +-------------+
// 4 | pc |
// +-------------+
// | |
// higher | expressions |
// addresses | |
// JS entry frames: When calling from C to JS, we construct two extra
// frames: An entry frame (C) and a trampoline frame (JS). The
// following pictures shows the two frames:
// lower | Stack |
// addresses | ^ |
// | | |
// | |
// | JS frame |
// | |
// | |
// ----------- +=============+ <--- sp (stack pointer)
// | |
// | parameters |
// t | |
// r +- - - - - - -+
// a | parameter0 |
// m +-------------+
// p | receiver |
// o +-------------+
// l | function |
// i +-------------+
// n -3 | code |
// e +-------------+
// -2 | NULL | context is always NULL
// +-------------+
// f -1 | 0 | args_length is always zero
// r +-------------+ <--- fp (frame pointer)
// a 0 | NULL | caller pp is always NULL for entries
// m +-------------+
// e 1 | caller_fp |
// +-------------+
// 2 | sp_on_exit | (caller_sp)
// +-------------+
// 3 | caller_pc |
// ----------- +=============+ <--- caller_sp == pp
// . ^
// . | try-handler, fake, not GC'ed
// . v
// +-------------+ <---
// -2 | next top pp |
// +-------------+
// -1 | next top fp |
// +-------------+ <--- fp
// | r4 | r4-r9 holding non-JS values must be preserved
// +-------------+
// J | r5 | before being initialized not to confuse GC
// S +-------------+
// | r6 |
// +-------------+
// e | r7 |
// n +-------------+
// t | r8 |
// r +-------------+
// y [ | r9 | ] only if r9 available
// +-------------+
// | r10 |
// f +-------------+
// r | r11 |
// a +-------------+
// m | caller_sp |
// e +-------------+
// | caller_pc |
// +-------------+ <--- caller_sp
// | argv | passed on stack from C code
// +-------------+
// | |
// higher | |
// addresses | C frame |
// The first 4 args are passed from C in r0-r3 and are not spilled on entry:
// r0: code entry
// r1: function
// r2: receiver
// r3: argc
// [sp+0]: argv
// C entry frames: When calling from JS to C, we construct one extra
// frame:
// lower | Stack |
// addresses | ^ |
// | | |
// | |
// | C frame |
// | |
// | |
// ----------- +=============+ <--- sp (stack pointer)
// | |
// | parameters | (first 4 args are passed in r0-r3)
// | |
// +-------------+ <--- fp (frame pointer)
// f 4/5 | caller_fp |
// r +-------------+
// a 5/6 | sp_on_exit | (pp)
// m +-------------+
// e 6/7 | caller_pc |
// +-------------+ <--- caller_sp (incl. parameters)
// 7/8 | |
// | parameters |
// | |
// +- - - - - - -+ <---
// -2 | parameter0 | ^
// +-------------+ | kParam0Offset
// -1 | receiver | v
// ----------- +=============+ <--- pp (parameter pointer, r10)
// 0 | function |
// +-------------+
// | |
// |caller-saved |
// | regs |
// | |
// +-------------+
// | |
// | caller |
// | expressions |
// | |
// higher | |
// addresses | JS frame |
} } // namespace v8::internal
#endif // V8_FRAMES_ARM_H_

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