Commit 7276f14c authored by kasper.lund's avatar kasper.lund

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.


git-svn-id: http://v8.googlecode.com/svn/trunk@8 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent af4734f1
2008-07-30: Version 0.2.0 (129146)
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 (128918)
Added support for storing JavaScript stack traces in a stack
......
......@@ -64,9 +64,6 @@ def GuessProcessor():
def GuessToolchain(os):
tools = Environment()['TOOLS']
if 'gcc' in tools:
if os == 'macos' and 'Kernel Version 8' in platform.version():
return 'gcc-darwin'
else:
return 'gcc'
elif 'msvc' in tools:
return 'msvc'
......@@ -79,19 +76,20 @@ def GetOptions():
os_guess = GuessOS()
toolchain_guess = GuessToolchain(os_guess)
processor_guess = GuessProcessor()
result.Add('mode', 'debug or release', 'release')
result.Add('toolchain', 'the toolchain to use (gcc, gcc-darwin or msvc)', toolchain_guess)
result.Add('os', 'the os to build for (linux, macos or win32)', os_guess)
result.Add('processor', 'the processor to build for (arm or ia32)', processor_guess)
result.Add('mode', 'compilation mode (debug, release)', 'release')
result.Add('toolchain', 'the toolchain to use (gcc, msvc)', toolchain_guess)
result.Add('os', 'the os to build for (linux, macos, win32)', os_guess)
result.Add('processor', 'the processor to build for (arm, ia32)', processor_guess)
result.Add('snapshot', 'build using snapshots for faster start-up (on, off)', 'off')
result.Add('library', 'which type of library to produce (static, shared, default)', 'default')
result.Add('sample', 'build sample (process, shell)', '')
return result
def VerifyOptions(env):
if not env['mode'] in ['debug', 'release']:
Abort("Unknown build mode '%s'." % env['mode'])
if not env['toolchain'] in ['gcc', 'gcc-darwin', 'msvc']:
if not env['toolchain'] in ['gcc', 'msvc']:
Abort("Unknown toolchain '%s'." % env['toolchain'])
if not env['os'] in ['linux', 'macos', 'win32']:
Abort("Unknown os '%s'." % env['os'])
......@@ -101,9 +99,11 @@ def VerifyOptions(env):
Abort("Illegal value for option snapshot: '%s'." % env['snapshot'])
if not env['library'] in ['static', 'shared', 'default']:
Abort("Illegal value for option library: '%s'." % env['library'])
if not env['sample'] in ['', 'process', 'shell']:
Abort("Illegal value for option sample: '%s'." % env['sample'])
def Start():
def Build():
opts = GetOptions()
env = Environment(options=opts)
Help(opts.GenerateHelpText(env))
......@@ -116,12 +116,38 @@ def Start():
use_snapshot = (env['snapshot'] == 'on')
library_type = env['library']
env.SConscript(
# Build the object files by invoking SCons recursively.
object_files = env.SConscript(
join('src', 'SConscript'),
build_dir=mode,
build_dir='build',
exports='toolchain arch os mode use_snapshot library_type',
duplicate=False
)
# Link the object files into a library.
if library_type == 'static':
library = env.StaticLibrary('v8', object_files)
elif library_type == 'shared':
# 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.
library = env.SharedLibrary('v8', object_files, PDB='v8.dll.pdb')
else:
library = env.Library('v8', object_files)
# Bail out if we're not building any sample.
sample = env['sample']
if not sample: return
# Build the sample.
env.Replace(CPPPATH='public')
object_path = join('build', 'samples', sample)
source_path = join('samples', sample + '.cc')
object = env.Object(object_path, source_path)
if toolchain == 'gcc':
env.Program(sample, [object, library], LIBS='pthread')
else:
env.Program(sample, [object, library], LIBS='WS2_32')
Start()
Build()
......@@ -41,14 +41,13 @@
*/
namespace v8 {
// Debug events which can occour in the V8 JavaScript engine.
// Debug events which can occur in the V8 JavaScript engine.
enum DebugEvent {
Break = 1,
Exception = 2,
NewFunction = 3,
BeforeCompile = 4,
AfterCompile = 5,
PendingRequestProcessed = 6
AfterCompile = 5
};
......@@ -72,6 +71,8 @@ typedef void (*DebugEventCallback)(DebugEvent event,
*
* \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);
......
......@@ -747,7 +747,7 @@ class String : public Primitive {
* be careful to supply the length parameter.
* If it is not given, the function calls
* 'strlen' to determine the buffer length, it might be
* wrong if '\0' character is in the 'data'.
* wrong if 'data' contains a null character.
*/
static Local<String> New(const char* data, int length = -1);
......@@ -777,10 +777,10 @@ class String : public Primitive {
*/
static Local<String> NewExternal(ExternalAsciiStringResource* resource);
/** Creates an undetectable string from the supplied character.*/
/** Creates an undetectable string from the supplied ascii or utf-8 data.*/
static Local<String> NewUndetectable(const char* data, int length = -1);
/** Creates an undetectable string from the supplied unsigned integer.*/
/** Creates an undetectable string from the supplied utf-16 data.*/
static Local<String> NewUndetectable(const uint16_t* data, int length = -1);
/**
......@@ -1562,13 +1562,6 @@ class Exception {
};
/**
* Ignore
*/
struct VersionInfo {
int major, minor, build_major, build_minor, revision;
};
// --- C o u n t e r s C a l l b a c k s
typedef int* (*CounterLookupCallback)(const wchar_t* name);
......@@ -1633,8 +1626,8 @@ class V8 {
*/
static void SetFlagsFromString(const char* str, int length);
/** Sets the version fields in the given VersionInfo struct.*/
static void GetVersion(VersionInfo* info);
/** Get the version string. */
static const char* GetVersion();
/**
* Enables the host application to provide a mechanism for recording
......@@ -1683,6 +1676,14 @@ class V8 {
*/
static bool Initialize();
/**
* Adjusts the about of registered external memory.
* Returns the adjusted value.
* Used for triggering a global GC earlier than otherwise.
*/
static int AdjustAmountOfExternalAllocatedMemory(int change_in_bytes);
private:
V8();
......
// Copyright 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.
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();
This diff is collapsed.
// Copyright 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.
#include <v8.h>
#include <cstring>
#include <cstdio>
void RunShell(v8::Handle<v8::Context> context);
bool ExecuteString(v8::Handle<v8::String> source);
v8::Handle<v8::Value> Print(const v8::Arguments& args);
v8::Handle<v8::String> ReadFile(const char* name);
int main(int argc, char* argv[]) {
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));
// Create a new execution environment containing the 'print' function.
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 {
v8::HandleScope handle_scope;
v8::Handle<v8::String> source = ReadFile(str);
if (source.IsEmpty()) {
printf("Error reading '%s'\n", str);
return 1;
}
if (!ExecuteString(source))
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::AsciiValue str(args[i]);
printf("%s", *str);
}
printf("\n");
return v8::Undefined();
}
// 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);
long 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));
}
printf("\n");
}
// Executes a string within the current v8 context.
bool ExecuteString(v8::Handle<v8::String> source) {
v8::HandleScope handle_scope;
v8::TryCatch try_catch;
v8::Handle<v8::Script> script = v8::Script::Compile(source);
if (script.IsEmpty()) {
// Print errors that happened during compilation.
v8::String::AsciiValue error(try_catch.Exception());
printf("%s\n", *error);
return false;
} else {
v8::Handle<v8::Value> result = script->Run();
if (result.IsEmpty()) {
// Print errors that happened during execution.
v8::String::AsciiValue error(try_catch.Exception());
printf("%s\n", *error);
return false;
} else {
if (!result->IsUndefined()) {
// If all went well and the result wasn't undefined then print
// the returned value.
v8::String::AsciiValue str(result);
printf("%s\n", *str);
}
return true;
}
}
}
......@@ -88,60 +88,6 @@ BUILD_OPTIONS_MAP = {
}
}
},
'gcc-darwin': {
'debug': {
'default': {
'CCFLAGS': '$DIALECTFLAGS $WARNINGFLAGS -g -O0',
'CPPDEFINES': ['ENABLE_LOGGING_AND_PROFILING', 'ENABLE_DISASSEMBLER', 'DEBUG'],
'CXXFLAGS': '$CCFLAGS -fno-rtti -fno-exceptions',
'DIALECTFLAGS': '-ansi',
'LIBS': 'pthread',
'WARNINGFLAGS': '-pedantic -Wall -W -Wno-unused-parameter -Werror'
},
'dtoa': {
'CCFLAGS': '$DIALECTFLAGS $WARNINGFLAGS -g -O0',
'CPPDEFINES': ['ENABLE_LOGGING_AND_PROFILING', 'ENABLE_DISASSEMBLER', 'DEBUG'],
'CXXFLAGS': '$CCFLAGS -fno-rtti -fno-exceptions',
'DIALECTFLAGS': '-ansi',
'LIBS': 'pthread',
'WARNINGFLAGS': '-Werror'
},
'jscre': {
'CCFLAGS': '$DIALECTFLAGS $WARNINGFLAGS -g -O0',
'CPPDEFINES': ['ENABLE_LOGGING_AND_PROFILING', 'ENABLE_DISASSEMBLER', 'DEBUG', 'SUPPORT_UTF8', 'NO_RECURSE', 'SUPPORT_UCP'],
'CXXFLAGS': '$CCFLAGS -fno-rtti -fno-exceptions',
'DIALECTFLAGS': '-ansi',
'LIBS': 'pthread',
'WARNINGFLAGS': '-w'
}
},
'release': {
'default': {
'CCFLAGS': '$DIALECTFLAGS $WARNINGFLAGS -O2',
'CPPDEFINES': ['ENABLE_LOGGING_AND_PROFILING'],
'CXXFLAGS': '$CCFLAGS -fno-rtti -fno-exceptions',
'DIALECTFLAGS': '-ansi',
'LIBS': 'pthread',
'WARNINGFLAGS': '-pedantic -Wall -W -Wno-unused-parameter -Werror'
},
'dtoa': {
'CCFLAGS': '$DIALECTFLAGS $WARNINGFLAGS -O2',
'CPPDEFINES': ['ENABLE_LOGGING_AND_PROFILING'],
'CXXFLAGS': '$CCFLAGS -fno-rtti -fno-exceptions',
'DIALECTFLAGS': '-ansi',
'LIBS': 'pthread',
'WARNINGFLAGS': '-Werror'
},
'jscre': {
'CCFLAGS': '$DIALECTFLAGS $WARNINGFLAGS -O2',
'CPPDEFINES': ['ENABLE_LOGGING_AND_PROFILING', 'SUPPORT_UTF8', 'NO_RECURSE', 'SUPPORT_UCP'],
'CXXFLAGS': '$CCFLAGS -fno-rtti -fno-exceptions',
'DIALECTFLAGS': '-ansi',
'LIBS': 'pthread',
'WARNINGFLAGS': '-w'
}
}
},
'msvc': {
'debug': {
'default': {
......@@ -240,6 +186,7 @@ conversions.cc
counters.cc
dateparser.cc
debug.cc
disassembler.cc
execution.cc
factory.cc
flags.cc
......@@ -282,8 +229,8 @@ zone.cc
PLATFORM_DEPENDENT_SOURCES = {
'arch:arm': ['assembler-arm.cc', 'builtins-arm.cc', 'codegen-arm.cc', 'cpu-arm.cc', 'disasm-arm.cc', 'disassembler-arm.cc', 'frames-arm.cc', 'ic-arm.cc', 'macro-assembler-arm.cc', 'simulator-arm.cc', 'stub-cache-arm.cc'],
'arch:ia32': ['assembler-ia32.cc', 'builtins-ia32.cc', 'codegen-ia32.cc', 'cpu-ia32.cc', 'disasm-ia32.cc', 'disassembler-ia32.cc', 'frames-ia32.cc', 'ic-ia32.cc', 'macro-assembler-ia32.cc', 'simulator-ia32.cc', 'stub-cache-ia32.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', 'simulator-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', 'simulator-ia32.cc', 'stub-cache-ia32.cc'],
'os:linux': ['platform-linux.cc'],
'os:macos': ['platform-macos.cc'],
'os:win32': ['platform-win32.cc']
......@@ -320,7 +267,7 @@ def Abort(message):
sys.exit(1)
def BuildObject(env, input, **kw):
def ConfigureObject(env, input, **kw):
if library_type == 'static':
return env.StaticObject(input, **kw)
elif library_type == 'shared':
......@@ -329,7 +276,7 @@ def BuildObject(env, input, **kw):
return env.Object(input, **kw)
def ConfigureBuild():
def ConfigureObjectFiles():
env = Environment()
options = BUILD_OPTIONS_MAP[toolchain][mode]['default']
env.Replace(**options)
......@@ -342,51 +289,44 @@ def ConfigureBuild():
source_files += PLATFORM_DEPENDENT_SOURCES["os:%s" % os]
full_source_files = [s for s in source_files]
# Combine the javascript library files into a single C++ file and
# 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)
libraries_obj = BuildObject(env, libraries_src, CPPPATH=['.'])
libraries_obj = ConfigureObject(env, libraries_src, CPPPATH=['.'])
# Build JSCRE.
jscre_env = env.Copy()
jscre_options = BUILD_OPTIONS_MAP[toolchain][mode]['jscre']
jscre_env.Replace(**jscre_options)
jscre_files = [join('third_party', 'jscre', s) for s in JSCRE_FILES]
jscre_obj = BuildObject(jscre_env, jscre_files)
jscre_obj = ConfigureObject(jscre_env, jscre_files)
# Build dtoa.
dtoa_env = env.Copy()
dtoa_options = BUILD_OPTIONS_MAP[toolchain][mode]['dtoa']
dtoa_env.Replace(**dtoa_options)
dtoa_files = ['dtoa-config.c']
dtoa_obj = BuildObject(dtoa_env, dtoa_files)
dtoa_obj = ConfigureObject(dtoa_env, dtoa_files)
full_source_objs = BuildObject(env, full_source_files)
full_source_objs = ConfigureObject(env, full_source_files)
non_snapshot_files = [jscre_obj, dtoa_obj, full_source_objs]
# Create snapshot if necessary.
empty_snapshot_obj = BuildObject(env, 'snapshot-empty.cc')
empty_snapshot_obj = ConfigureObject(env, 'snapshot-empty.cc')
if 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 = BuildObject(env, snapshot_cc, CPPPATH=['.'])
libraries_obj = BuildObject(env, libraries_empty_src, CPPPATH=['.'])
snapshot_obj = ConfigureObject(env, snapshot_cc, CPPPATH=['.'])
libraries_obj = ConfigureObject(env, libraries_empty_src, CPPPATH=['.'])
else:
snapshot_obj = empty_snapshot_obj
all_files = [non_snapshot_files, libraries_obj, snapshot_obj]
if library_type == 'static':
env.StaticLibrary('v8', all_files)
elif library_type == 'shared':
# 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.
env.SharedLibrary('v8', all_files, PDB='v8.dll.pdb')
else:
env.Library('v8', all_files)
# Return all the object files needed to link the library.
return [non_snapshot_files, libraries_obj, snapshot_obj]
ConfigureBuild()
object_files = ConfigureObjectFiles()
Return('object_files')
......@@ -2090,6 +2090,11 @@ bool v8::V8::Initialize() {
}
const char* v8::V8::GetVersion() {
return "0.2.0 (129146)";
}
Persistent<Context> v8::Context::New(v8::ExtensionConfiguration* extensions,
v8::Handle<ObjectTemplate> global_template,
v8::Handle<Value> global_object) {
......@@ -2473,6 +2478,12 @@ void V8::AddObjectToGroup(void* group_id, Persistent<Object> obj) {
}
int V8::AdjustAmountOfExternalAllocatedMemory(int change_in_bytes) {
if (IsDeadCheck("v8::V8::AdjustAmountOfExternalAllocatedMemory()")) return 0;
return i::Heap::AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
}
void V8::SetGlobalGCPrologueCallback(GCCallback callback) {
if (IsDeadCheck("v8::V8::SetGlobalGCPrologueCallback()")) return;
i::Heap::SetGlobalGCPrologueCallback(callback);
......
......@@ -1084,7 +1084,14 @@ void Assembler::swpb(Register dst,
// Exception-generating instructions and debugging support
void Assembler::stop(const char* msg) {
#if !defined(__arm__)
// The simulator handles these special instructions and stops execution.
emit(15 << 28 | ((intptr_t) msg));
#else
// Just issue a simple break instruction for now. Alternatively we could use
// the swi(0x9f0001) instruction on Linux.
bkpt(0);
#endif
}
......
......@@ -503,16 +503,9 @@ class Assembler : public Malloced {
// Exception-generating instructions and debugging support
void stop(const char* msg);
void untested(const char* msg);
void unimplemented(const char* msg);
void unreachable(const char* msg);
void bkpt(uint32_t imm16); // v5 and above
void swi(uint32_t imm24, Condition cond = al);
// To generate a breakpoint on ARM Linux you can use swi(0x9f0001).
// For some reason stepi or cont will not work in gdb until you have done:
// set $pc = $pc + 4
inline void int3() { swi(0x9f0001); }
// Coprocessor instructions
......
......@@ -204,12 +204,31 @@ 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);
......
......@@ -135,37 +135,9 @@ void CpuFeatures::Probe() {
// -----------------------------------------------------------------------------
// 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 3 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 {
private:
enum Type {
UNCONDITIONAL_JUMP,
OTHER
};
int data_;
// Implementation of Displacement
class TypeField: public BitField<Type, 0, 1> {};
class NextField: public BitField<int, 1, 32-1> {};
void init(Label* L, Type type) {
void Displacement::init(Label* L, Type type) {
ASSERT(!L->is_bound());
int next = 0;
if (L->is_linked()) {
......@@ -175,45 +147,7 @@ class Displacement BASE_EMBEDDED {
// Ensure that we _never_ overflow the next field.
ASSERT(NextField::is_valid(Assembler::kMaximalBufferSize));
data_ = NextField::encode(next) | TypeField::encode(type);
}
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_));
}
friend class Assembler;
friend class MacroAssembler;
};
// TODO(1236137): Stop using macros here. The reason for using them is
// to avoid declaring the Displacement class in the .h file and have
// functions on the assembler that returns them. Maybe that's not a
// big issue?
#define disp_at(L) \
Displacement(long_at((L)->pos()))
#define disp_at_put(L, disp) \
long_at_put((L)->pos(), (disp).data())
#define emit_disp(L, type) { \
Displacement disp((L), (type)); \
(L)->link_to(pc_offset()); \
emit(static_cast<int>(disp.data())); \
}
}
// -----------------------------------------------------------------------------
......
......@@ -264,6 +264,59 @@ class Operand BASE_EMBEDDED {
};
// -----------------------------------------------------------------------------
// 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:
......@@ -709,6 +762,11 @@ class Assembler : public Malloced {
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(RelocMode rmode, intptr_t data = 0);
......
......@@ -143,7 +143,7 @@ static const int kNoPosition = -1;
enum RelocMode {
// Please note the order is important (see is_code_target).
// Please note the order is important (see is_code_target, is_gc_reloc_mode).
js_construct_call, // code target that is an exit JavaScript frame stub.
exit_js_frame, // code target that is an exit JavaScript frame stub.
code_target_context, // code target used for contextual loads.
......@@ -163,7 +163,8 @@ enum RelocMode {
// Pseudo-types
reloc_mode_count,
last_code_enum = code_target
last_code_enum = code_target,
last_gced_enum = embedded_string
};
......@@ -187,6 +188,12 @@ inline bool is_code_target(RelocMode mode) {
}
// Is the relocation mode affected by GC?
inline bool is_gc_reloc_mode(RelocMode mode) {
return mode <= last_gced_enum;
}
inline bool is_js_return(RelocMode mode) {
return mode == js_return;
}
......
......@@ -491,8 +491,12 @@ void Genesis::CreateRoots(v8::Handle<v8::ObjectTemplate> global_template,
{ // --- E m p t y ---
Handle<Code> call_code =
Handle<Code>(Builtins::builtin(Builtins::EmptyFunction));
Handle<String> source = Factory::NewStringFromAscii(CStrVector("() {}"));
empty_function->set_code(*call_code);
empty_function->shared()->set_script(*Factory::NewScript(source));
empty_function->shared()->set_start_position(0);
empty_function->shared()->set_end_position(source->length());
global_context()->function_map()->set_prototype(*empty_function);
global_context()->function_instance_map()->set_prototype(*empty_function);
......@@ -1209,11 +1213,11 @@ void Genesis::TransferObject(Handle<JSObject> from, Handle<JSObject> to) {
void Genesis::MakeFunctionInstancePrototypeWritable() {
// Make a new function map so all future functions
// will have settable prototype properties.
// will have settable and enumerable prototype properties.
HandleScope scope;
Handle<DescriptorArray> function_map_descriptors =
ComputeFunctionInstanceDescriptor(false);
ComputeFunctionInstanceDescriptor(false, true);
Handle<Map> fm = Factory::CopyMap(Top::function_map());
fm->set_instance_descriptors(*function_map_descriptors);
Top::context()->global_context()->set_function_map(*fm);
......
......@@ -47,7 +47,7 @@ void Builtins::Generate_Adaptor(MacroAssembler* masm,
void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
// r0: number of arguments
__ EnterJSFrame(0, 0);
__ EnterJSFrame(0);
// Allocate the new receiver object.
__ push(r0);
......@@ -119,7 +119,7 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
// Remove receiver from the stack, remove caller arguments, and
// return.
__ bind(&exit);
__ ExitJSFrame(RETURN, 0);
__ ExitJSFrame(RETURN);
// Compute the offset from the beginning of the JSConstructCall
// builtin code object to the return address after the call.
......@@ -221,13 +221,13 @@ void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
// TODO(1233523): Implement. Unused for now.
__ int3();
__ stop("Builtins::Generate_FunctionApply");
}
void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
// TODO(1233523): Implement. Unused for now.
__ int3();
__ stop("Builtins::Generate_ArgumentsAdaptorTrampoline");
Label return_site;
__ bind(&return_site);
......@@ -269,9 +269,9 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
__ 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, prolog_pc
// sp_on_exit (ip == pp), return address
__ stm(db_w, sp, r2.bit() | r3.bit() | pp.bit() | fp.bit() |
ip.bit() | lr.bit() | pc.bit());
ip.bit() | lr.bit());
// Setup new frame pointer.
__ add(fp, sp, Operand(-StandardFrameConstants::kContextOffset));
__ mov(pp, Operand(ip)); // setup new parameter pointer
......
......@@ -50,33 +50,21 @@ Handle<Code> CodeStub::GetCode() {
// Generate the new code.
MacroAssembler masm(NULL, 256);
bool needs_check_for_stub_calls = !AllowsStubCalls();
if (needs_check_for_stub_calls) {
// Nested stubs are not allowed for leafs.
ASSERT(!masm.generating_stub());
masm.set_generating_stub(true);
}
masm.set_allow_stub_calls(AllowsStubCalls());
// Generate the code for the stub.
masm.set_generating_stub(true);
Generate(&masm);
if (needs_check_for_stub_calls) masm.set_generating_stub(false);
// Create the code object.
CodeDesc desc;
masm.GetCode(&desc);
// Copy the generated code into a heap object.
// TODO(1238541): Simplify this somewhat complicated encoding.
CodeStub::Major major = MajorKey();
// Lower three bits in state field.
InlineCacheState state = static_cast<InlineCacheState>(major & 0x07);
// Upper two bits in type field.
PropertyType type = static_cast<PropertyType>((major >> 3) & 0x03);
// Compute flags with state and type used to hold majr key.
Code::Flags flags = Code::ComputeFlags(Code::STUB, state, type);
// 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);
......@@ -110,22 +98,22 @@ const char* CodeStub::MajorName(CodeStub::Major major_key) {
switch (major_key) {
case CallFunction:
return "CallFunction";
case InlinedGenericOp:
return "InlinedGenericOp";
case GenericBinaryOp:
return "GenericBinaryOp";
case SmiOp:
return "SmiOp";
case Compare:
return "Compare";
case RecordWrite:
return "RecordWrite";
case GenericOp:
return "GenericOp";
case StackCheck:
return "StackCheck";
case UnarySub:
return "UnarySub";
case RevertToNumber:
return "RevertToNumber";
case ToBoolean:
return "ToBoolean";
case CounterOp:
return "CounterOp";
case ArgumentsAccess:
......
......@@ -36,14 +36,14 @@ class CodeStub BASE_EMBEDDED {
public:
enum Major {
CallFunction,
InlinedGenericOp,
GenericBinaryOp,
SmiOp,
Compare,
RecordWrite, // Last stub that allows stub calls inside.
GenericOp,
StackCheck,
UnarySub,
RevertToNumber,
ToBoolean,
CounterOp,
ArgumentsAccess,
Runtime,
......
This diff is collapsed.
This diff is collapsed.
......@@ -251,7 +251,9 @@ bool CodeGenerator::CheckForInlineRuntimeCall(CallRuntime* node) {
{&v8::internal::CodeGenerator::GenerateValueOf,
"_ValueOf"},
{&v8::internal::CodeGenerator::GenerateSetValueOf,
"_SetValueOf"}
"_SetValueOf"},
{&v8::internal::CodeGenerator::GenerateFastCharCodeAt,
"_FastCharCodeAt"}
};
if (node->name()->length() > 0 && node->name()->Get(0) == '_') {
for (unsigned i = 0;
......@@ -278,15 +280,4 @@ void RuntimeStub::Generate(MacroAssembler* masm) {
}
const char* GenericOpStub::GetName() {
switch (op_) {
case Token::ADD: return "GenericOpStub_ADD";
case Token::SUB: return "GenericOpStub_SUB";
case Token::MUL: return "GenericOpStub_MUL";
case Token::DIV: return "GenericOpStub_DIV";
default: return "GenericOpStub";
}
}
} } // namespace v8::internal
......@@ -169,6 +169,9 @@ class CodeGenerator: public Visitor {
virtual void GenerateValueOf(ZoneList<Expression*>* args) = 0;
virtual void GenerateSetValueOf(ZoneList<Expression*>* args) = 0;
// Fast support for charCodeAt(n).
virtual void GenerateFastCharCodeAt(ZoneList<Expression*>* args) = 0;
private:
bool is_eval_; // Tells whether code is generated for eval.
Handle<Script> script_;
......@@ -199,25 +202,6 @@ class RuntimeStub : public CodeStub {
};
class GenericOpStub : public CodeStub {
public:
explicit GenericOpStub(Token::Value op) : op_(op) { }
private:
Token::Value op_;
Major MajorKey() { return GenericOp; }
int MinorKey() { return static_cast<int>(op_); }
void Generate(MacroAssembler* masm);
const char* GetName();
#ifdef DEBUG
void Print() { PrintF("GenericOpStub (token %s)\n", Token::String(op_)); }
#endif
};
class StackCheckStub : public CodeStub {
public:
StackCheckStub() { }
......
......@@ -35,126 +35,6 @@
namespace v8 { namespace internal {
// Helper class for building result strings in a character buffer. The
// purpose of the class is to use safe operations that checks the
// buffer bounds on all operations in debug mode.
class StringBuilder {
public:
// Create a string builder with a buffer of the given size. The
// buffer is allocated through NewArray<char> and must be
// deallocated by the caller of Finalize().
explicit StringBuilder(int size);
StringBuilder(char* buffer, int size)
: buffer_(buffer), size_(size), position_(0) { }
~StringBuilder() { if (!is_finalized()) Finalize(); }
// Get the current position in the builder.
inline int position() const;
// Add a single character to the builder. It is not allowed to add
// 0-characters; use the Finalize() method to terminate the string
// instead.
inline void AddCharacter(char c);
// Add an entire string to the builder. Uses strlen() internally to
// compute the length of the input string.
void AddString(const char* s);
// Add the first 'n' characters of the given string 's' to the
// builder. The input string must have enough characters.
void AddSubstring(const char* s, int n);
// Add formatted contents to the builder just like printf().
void AddFormatted(const char* format, ...);
// Add character padding to the builder. If count is non-positive,
// nothing is added to the builder.
void AddPadding(char c, int count);
// Finalize the string by 0-terminating it and returning the buffer.
char* Finalize();
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder);
char* buffer_;
int size_;
int position_;
bool is_finalized() const { return position_ < 0; }
};
StringBuilder::StringBuilder(int size) {
buffer_ = NewArray<char>(size);
size_ = size;
position_ = 0;
}
inline int StringBuilder::position() const {
ASSERT(!is_finalized());
return position_;
}
inline void StringBuilder::AddCharacter(char c) {
ASSERT(c != '\0');
ASSERT(!is_finalized() && position_ < size_);
buffer_[position_++] = c;
}
void StringBuilder::AddString(const char* s) {
AddSubstring(s, strlen(s));
}
void StringBuilder::AddSubstring(const char* s, int n) {
ASSERT(!is_finalized() && position_ + n < size_);
ASSERT(static_cast<size_t>(n) <= strlen(s));
memcpy(&buffer_[position_], s, n * kCharSize);
position_ += n;
}
void StringBuilder::AddFormatted(const char* format, ...) {
ASSERT(!is_finalized() && position_ < size_);
va_list args;
va_start(args, format);
int remaining = size_ - position_;
int n = OS::VSNPrintF(&buffer_[position_], remaining, format, args);
va_end(args);
if (n < 0 || n >= remaining) {
position_ = size_;
} else {
position_ += n;
}
}
void StringBuilder::AddPadding(char c, int count) {
for (int i = 0; i < count; i++) {
AddCharacter(c);
}
}
char* StringBuilder::Finalize() {
ASSERT(!is_finalized() && position_ < size_);
buffer_[position_] = '\0';
// Make sure nobody managed to add a 0-character to the
// buffer while building the string.
ASSERT(strlen(buffer_) == static_cast<size_t>(position_));
position_ = -1;
ASSERT(is_finalized());
return buffer_;
}
int HexValue(uc32 c) {
if ('0' <= c && c <= '9')
return c - '0';
......
......@@ -26,8 +26,9 @@
// 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"
......
This diff is collapsed.
......@@ -234,7 +234,7 @@ class Debug {
return reinterpret_cast<Address *>(&registers_[r]);
}
// Addres of the debug break return entry code.
// 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.
......@@ -321,14 +321,11 @@ class Debug {
};
class PendingRequest;
class DebugMessageThread;
class Debugger {
public:
static void DebugRequest(const uint16_t* json_request, int length);
static bool ProcessPendingRequests();
static Handle<Object> MakeJSObject(Vector<const char> constructor_name,
int argc, Object*** argv,
......@@ -357,7 +354,6 @@ class Debugger {
static void OnAfterCompile(Handle<Script> script,
Handle<JSFunction> fun);
static void OnNewFunction(Handle<JSFunction> fun);
static void OnPendingRequestProcessed(Handle<Object> event_data);
static void ProcessDebugEvent(v8::DebugEvent event,
Handle<Object> event_data);
static void SetMessageHandler(v8::DebugMessageHandler handler, void* data);
......@@ -384,68 +380,91 @@ class Debugger {
static DebugMessageThread* message_thread_;
static v8::DebugMessageHandler debug_message_handler_;
static void* debug_message_handler_data_;
// Head and tail of linked list of pending commands. The list is protected
// by a mutex as it can be updated/read from different threads.
static Mutex* pending_requests_access_;
static PendingRequest* pending_requests_head_;
static PendingRequest* pending_requests_tail_;
};
// Linked list of pending requests issued by debugger while V8 was running.
class PendingRequest {
// A Queue of Vector<uint16_t> objects. A thread-safe version is
// LockingMessageQueue, based on this class.
class MessageQueue BASE_EMBEDDED {
public:
PendingRequest(const uint16_t* json_request, int length);
~PendingRequest();
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.
};
PendingRequest* next() { return next_; }
void set_next(PendingRequest* next) { next_ = next; }
Handle<String> request();
// 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.
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:
Vector<uint16_t> json_request_; // Request string.
PendingRequest* next_; // Next pointer for linked list.
// Logs a timestamp, operation name, and operation argument
void LogQueueOperation(const char* operation_name,
Vector<uint16_t> parameter);
MessageQueue queue_;
Mutex* lock_;
DISALLOW_EVIL_CONSTRUCTORS(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();
virtual ~DebugMessageThread();
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);
void SetEventJSON(Vector<uint16_t> event_json);
// 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);
void SetCommand(Vector<uint16_t> command);
void SetResult(const char* result);
void SetResult(Vector<uint16_t> result);
void CommandResult(Vector<uint16_t> result);
// 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();
protected:
// Main function of DebugMessageThread thread.
void Run();
void HandleCommand();
bool host_running_; // Is the debugging host running or stopped
v8::DebugEvent event_; // Active event
Semaphore* command_received_; // Signal from the telnet connection
Semaphore* debug_event_; // Signal from the V8 thread
Semaphore* debug_command_; // Signal to the V8 thread
Semaphore* debug_result_; // Signal from the V8 thread
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:
void SetVector(Vector<uint16_t>* vector, Vector<uint16_t> value);
bool TwoByteEqualsAscii(Vector<uint16_t> two_byte, const char* ascii);
Vector<uint16_t> event_json_; // Active event JSON.
Vector<uint16_t> command_; // Current command.
Vector<uint16_t> result_; // Result of processing command.
static const int kQueueInitialSize = 4;
LockingMessageQueue command_queue_;
LockingMessageQueue message_queue_;
DISALLOW_EVIL_CONSTRUCTORS(DebugMessageThread);
};
......
......@@ -145,7 +145,11 @@ void Decoder::PrintShiftRm(Instr* instr) {
int rm = instr->RmField();
PrintRegister(rm);
if ((shift != LSL) || (shift_amount != 0)) {
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)) {
......@@ -166,7 +170,6 @@ void Decoder::PrintShiftRm(Instr* instr) {
", %s ", shift_names[shift]);
PrintRegister(rs);
}
}
}
......@@ -799,6 +802,11 @@ void Decoder::DecodeType7(Instr* 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_,
out_buffer_size_ - out_buffer_pos_,
"%08x ",
instr->InstructionBits());
if (instr->ConditionField() == special_condition) {
Format(instr, "break 'msg");
return Instr::kInstrSize;
......@@ -921,6 +929,16 @@ int Disassembler::InstructionDecode(char* buffer, const int buffer_size,
}
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;) {
......@@ -928,16 +946,8 @@ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
buffer[0] = '\0';
byte* prev_pc = pc;
pc += d.InstructionDecode(buffer, sizeof buffer, pc);
fprintf(f, "%p", prev_pc);
fprintf(f, " ");
for (byte* bp = prev_pc; bp < pc; bp++) {
fprintf(f, "%02x", *bp);
}
for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
fprintf(f, " ");
}
fprintf(f, " %s\n", buffer);
fprintf(f, "%p %08x %s\n",
prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer);
}
}
......
......@@ -28,28 +28,12 @@
#include <assert.h>
#include <stdio.h>
#include <stdarg.h>
#ifndef WIN32
#include <stdint.h>
#endif
#include "v8.h"
#include "disasm.h"
namespace disasm {
// Windows is missing the stdint.h header file
#ifdef WIN32
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef int int32_t;
#endif
#define UNIMPLEMENTED() \
assert(false)
#define UNREACHABLE() \
assert(false)
enum OperandOrder {
UNSET_OP_ORDER = 0,
REG_OPER_OP_ORDER,
......@@ -653,6 +637,7 @@ int DisassemblerIA32::FPUInstruction(byte* data) {
const char* mnem = "?";
switch (regop) {
case eax: mnem = "fild_s"; break;
case edx: mnem = "fist_s"; break;
case ebx: mnem = "fistp_s"; break;
default: UnimplementedInstruction();
}
......@@ -691,6 +676,10 @@ int DisassemblerIA32::FPUInstruction(byte* data) {
}
AppendToBuffer("%s%s st%d", mnem, is_pop ? "p" : "", b2 & 0x7);
return 2;
} else if (b1 == 0xDA && b2 == 0xE9) {
const char* mnem = "fucompp";
AppendToBuffer("%s", mnem);
return 2;
}
AppendToBuffer("Unknown FP instruction");
return 2;
......@@ -965,6 +954,7 @@ int DisassemblerIA32::InstructionDecode(char* out_buffer,
break;
case 0xD9: // fall through
case 0xDA: // fall through
case 0xDB: // fall through
case 0xDC: // fall through
case 0xDD: // fall through
......@@ -1044,12 +1034,26 @@ int DisassemblerIA32::InstructionDecode(char* out_buffer,
}
int instr_len = data - instr;
if (instr_len == 0) instr_len = 1; // parse at least a byte
#ifdef WIN32
_snprintf(out_buffer, out_buffer_size, "%s", tmp_buffer_);
#else
snprintf(out_buffer, out_buffer_size, "%s", tmp_buffer_);
#endif
ASSERT(instr_len > 0); // Ensure progress.
int outp = 0;
// Instruction bytes.
for (byte* bp = instr; bp < data; bp++) {
outp += v8::internal::OS::SNPrintF(out_buffer + outp,
out_buffer_size - outp,
"%02x",
*bp);
}
for (int i = 6 - instr_len; i >= 0; i--) {
outp += v8::internal::OS::SNPrintF(out_buffer + outp,
out_buffer_size - outp,
" ");
}
outp += v8::internal::OS::SNPrintF(out_buffer + outp,
out_buffer_size - outp,
" %s",
tmp_buffer_);
return instr_len;
}
......@@ -1124,6 +1128,10 @@ int Disassembler::InstructionDecode(char* buffer,
}
// The IA-32 assembler does not currently use constant pools.
int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
/*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
Disassembler d;
for (byte* pc = begin; pc < end;) {
......
......@@ -61,6 +61,10 @@ class Disassembler {
// Returns the length of the disassembled machine instruction in bytes.
int InstructionDecode(char* buffer, const int buffer_size, 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);
......
// 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.
#include "v8.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 char buffer[128];
const char* name = Builtins::Lookup(pc);
if (name != NULL) {
OS::SNPrintF(buffer, sizeof buffer, "%s (%p)", name, pc);
return buffer;
}
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, sizeof buffer, "%d (%p)", offs, pc);
return buffer;
}
}
return disasm::NameConverter::NameOfAddress(pc);
}
const char* V8NameConverter::NameInCode(byte* addr) const {
// If 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 = 1024;
static const int kRelocInfoPosition = 57;
static int DecodeIt(FILE* f,
const V8NameConverter& converter,
byte* begin,
byte* end) {
ExternalReferenceEncoder ref_encoder;
char decode_buffer[128];
char out_buffer[kOutBufferSize];
const int sob = sizeof 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, sizeof(decode_buffer), "%s", "constant");
constants--;
pc += 4;
} else {
int instruction_bits = *(reinterpret_cast<int*>(pc));
if ((instruction_bits & 0xfff00000) == 0x03000000) {
OS::SNPrintF(decode_buffer, sizeof(decode_buffer),
"%s", "constant pool begin");
constants = instruction_bits & 0x0000ffff;
pc += 4;
} else {
decode_buffer[0] = '\0';
pc += d.InstructionDecode(decode_buffer, sizeof decode_buffer, pc);
}
}
// Collect RelocInfo for this instruction (prev_pc .. pc-1)
List<const char*> comments(4);
List<byte*> pcs(1);
List<RelocMode> rmodes(1);
List<intptr_t> datas(1);
if (it != NULL) {
while (!it->done() && it->rinfo()->pc() < pc) {
if (is_comment(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();
}
}
int outp = 0; // pointer into out_buffer, implements append operation.
// Comments.
for (int i = 0; i < comments.length(); i++) {
outp += OS::SNPrintF(out_buffer + outp, sob - outp,
" %s\n", comments[i]);
}
// Write out comments, resets outp so that we can format the next line.
if (outp > 0) {
DumpBuffer(f, out_buffer);
outp = 0;
}
// Instruction address and instruction offset.
outp += OS::SNPrintF(out_buffer + outp, sob - outp,
"%p %4d ", prev_pc, prev_pc - begin);
// Instruction bytes.
ASSERT(pc - prev_pc == 4);
outp += OS::SNPrintF(out_buffer + outp,
sob - outp,
"%08x",
*reinterpret_cast<intptr_t*>(prev_pc));
for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
outp += OS::SNPrintF(out_buffer + outp, sob - outp, " ");
}
outp += OS::SNPrintF(out_buffer + outp, sob - outp, " %s", decode_buffer);
// 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.
for (int p = outp; p < kRelocInfoPosition; p++) {
outp += OS::SNPrintF(out_buffer + outp, sob - outp, " ");
}
} else {
// Additional reloc infos are printed on separate lines.
outp += OS::SNPrintF(out_buffer + outp, sob - outp, "\n");
for (int p = 0; p < kRelocInfoPosition; p++) {
outp += OS::SNPrintF(out_buffer + outp, sob - outp, " ");
}
}
if (is_position(relocinfo.rmode())) {
outp += OS::SNPrintF(out_buffer + outp,
sob - outp,
" ;; debug: statement %d",
relocinfo.data());
} else if (relocinfo.rmode() == embedded_object) {
HeapStringAllocator allocator;
StringStream accumulator(&allocator);
relocinfo.target_object()->ShortPrint(&accumulator);
SmartPointer<char> obj_name = accumulator.ToCString();
outp += OS::SNPrintF(out_buffer + outp, sob - outp,
" ;; object: %s",
*obj_name);
} else if (relocinfo.rmode() == external_reference) {
const char* reference_name =
ref_encoder.NameOfAddress(*relocinfo.target_reference_address());
outp += OS::SNPrintF(out_buffer + outp, sob - outp,
" ;; external reference (%s)",
reference_name);
} else if (relocinfo.rmode() == code_target) {
outp +=
OS::SNPrintF(out_buffer + outp, sob - outp,
" ;; code target (%s)",
converter.NameOfAddress(relocinfo.target_address()));
} else {
outp += OS::SNPrintF(out_buffer + outp, sob - outp,
" ;; %s%s",
#if defined(DEBUG)
RelocInfo::RelocModeName(relocinfo.rmode()),
#else
"reloc_info",
#endif
"");
}
}
outp += OS::SNPrintF(out_buffer + outp, sob - outp, "\n");
if (outp > 0) {
ASSERT(outp < kOutBufferSize);
DumpBuffer(f, out_buffer);
outp = 0;
}
}
delete it;
return pc - begin;
}
int Disassembler::Decode(FILE* f, byte* begin, byte* end) {
V8NameConverter defaultConverter(NULL);
return DecodeIt(f, defaultConverter, begin, end);
}
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
......@@ -54,6 +54,7 @@ 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_;
......@@ -82,12 +83,22 @@ const char* V8NameConverter::NameOfAddress(byte* pc) const {
}
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);
if (f == NULL) {
PrintF("%s", buff);
} else {
fprintf(f, "%s", buff);
}
}
static const int kOutBufferSize = 1024;
static const int kOutBufferSize = 256 + String::kMaxShortPrintLength;
static const int kRelocInfoPosition = 57;
static int DecodeIt(FILE* f,
......@@ -100,7 +111,6 @@ static int DecodeIt(FILE* f,
char decode_buffer[128];
char out_buffer[kOutBufferSize];
const int sob = sizeof out_buffer;
byte* pc = begin;
disasm::Disassembler d(converter);
RelocIterator* it = NULL;
......@@ -109,12 +119,32 @@ static int DecodeIt(FILE* f,
} 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,
sizeof(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,
sizeof(decode_buffer),
"%08x constant pool begin",
*reinterpret_cast<int32_t*>(pc));
constants = num_const;
pc += 4;
} else {
decode_buffer[0] = '\0';
pc += d.InstructionDecode(decode_buffer, sizeof decode_buffer, pc);
}
}
// Collect RelocInfo for this instruction (prev_pc .. pc-1)
List<const char*> comments(4);
......@@ -136,32 +166,22 @@ static int DecodeIt(FILE* f,
}
}
int outp = 0; // pointer into out_buffer, implements append operation.
StringBuilder out(out_buffer, sizeof(out_buffer));
// Comments.
for (int i = 0; i < comments.length(); i++) {
outp += OS::SNPrintF(out_buffer + outp, sob - outp,
" %s\n", comments[i]);
out.AddFormatted(" %s\n", comments[i]);
}
// Write out comments, resets outp so that we can format the next line.
if (outp > 0) {
DumpBuffer(f, out_buffer);
outp = 0;
}
DumpBuffer(f, out.Finalize());
out.Reset();
// Instruction address and instruction offset.
outp += OS::SNPrintF(out_buffer + outp, sob - outp,
"%p %4d ", prev_pc, prev_pc - begin);
out.AddFormatted("%p %4d ", prev_pc, prev_pc - begin);
// Instruction bytes.
for (byte* bp = prev_pc; bp < pc; bp++) {
outp += OS::SNPrintF(out_buffer + outp, sob - outp, "%02x", *bp);
}
for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
outp += OS::SNPrintF(out_buffer + outp, sob - outp, " ");
}
outp += OS::SNPrintF(out_buffer + outp, sob - outp, " %s", decode_buffer);
// Instruction.
out.AddFormatted("%s", decode_buffer);
// Print all the reloc info for this instruction which are not comments.
for (int i = 0; i < pcs.length(); i++) {
......@@ -171,39 +191,27 @@ static int DecodeIt(FILE* f,
// Indent the printing of the reloc info.
if (i == 0) {
// The first reloc info is printed after the disassembled instruction.
for (int p = outp; p < kRelocInfoPosition; p++) {
outp += OS::SNPrintF(out_buffer + outp, sob - outp, " ");
}
out.AddPadding(' ', kRelocInfoPosition - out.position());
} else {
// Additional reloc infos are printed on separate lines.
outp += OS::SNPrintF(out_buffer + outp, sob - outp, "\n");
for (int p = 0; p < kRelocInfoPosition; p++) {
outp += OS::SNPrintF(out_buffer + outp, sob - outp, " ");
}
out.AddFormatted("\n");
out.AddPadding(' ', kRelocInfoPosition);
}
if (is_position(relocinfo.rmode())) {
outp += OS::SNPrintF(out_buffer + outp,
sob - outp,
" ;; debug: statement %d",
relocinfo.data());
out.AddFormatted(" ;; debug: statement %d", relocinfo.data());
} else if (relocinfo.rmode() == embedded_object) {
HeapStringAllocator allocator;
StringStream accumulator(&allocator);
relocinfo.target_object()->ShortPrint(&accumulator);
SmartPointer<char> obj_name = accumulator.ToCString();
outp += OS::SNPrintF(out_buffer + outp, sob - outp,
" ;; object: %s",
*obj_name);
out.AddFormatted(" ;; object: %s", *obj_name);
} else if (relocinfo.rmode() == external_reference) {
const char* reference_name =
ref_encoder.NameOfAddress(*relocinfo.target_reference_address());
outp += OS::SNPrintF(out_buffer + outp, sob - outp,
" ;; external reference (%s)",
reference_name);
out.AddFormatted(" ;; external reference (%s)", reference_name);
} else {
outp += OS::SNPrintF(out_buffer + outp, sob - outp,
" ;; %s",
out.AddFormatted(" ;; %s",
RelocInfo::RelocModeName(relocinfo.rmode()));
if (is_code_target(relocinfo.rmode())) {
Code* code = Debug::GetCodeTarget(relocinfo.target_address());
......@@ -219,45 +227,32 @@ static int DecodeIt(FILE* f,
CodeStub::Major major_key = code->major_key();
uint32_t minor_key = CodeStub::MinorKeyFromKey(key);
ASSERT(major_key == CodeStub::MajorKeyFromKey(key));
outp += OS::SNPrintF(out_buffer + outp, sob - outp,
" (%s, %s, ",
out.AddFormatted(" (%s, %s, ",
Code::Kind2String(kind),
CodeStub::MajorName(code->major_key()));
switch (code->major_key()) {
case CodeStub::CallFunction:
outp += OS::SNPrintF(out_buffer + outp, sob - outp,
"argc = %d)",
minor_key);
out.AddFormatted("argc = %d)", minor_key);
break;
case CodeStub::Runtime: {
Runtime::FunctionId id =
static_cast<Runtime::FunctionId>(minor_key);
outp += OS::SNPrintF(out_buffer + outp, sob - outp,
"%s)",
Runtime::FunctionForId(id)->name);
out.AddFormatted("%s)", Runtime::FunctionForId(id)->name);
break;
}
default:
outp += OS::SNPrintF(out_buffer + outp, sob - outp,
"minor: %d)",
minor_key);
out.AddFormatted("minor: %d)", minor_key);
}
}
} else {
outp += OS::SNPrintF(out_buffer + outp, sob - outp,
" (%s)",
Code::Kind2String(kind));
}
out.AddFormatted(" (%s)", Code::Kind2String(kind));
}
}
}
outp += OS::SNPrintF(out_buffer + outp, sob - outp, "\n");
if (outp > 0) {
ASSERT(outp < kOutBufferSize);
DumpBuffer(f, out_buffer);
outp = 0;
}
out.AddString("\n");
DumpBuffer(f, out.Finalize());
out.Reset();
}
delete it;
......@@ -271,13 +266,14 @@ int Disassembler::Decode(FILE* f, byte* begin, byte* end) {
}
// Called by Code::CodePrint
// 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) {}
......
......@@ -200,8 +200,11 @@ StackGuard::StackGuard() {
thread_local_.initial_jslimit_ = thread_local_.jslimit_ =
GENERATED_CODE_STACK_LIMIT(kLimitSize);
// NOTE: The check for overflow is not safe as there is no guarentee 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 ?
reinterpret_cast<uintptr_t>(this) - kLimitSize : 0;
if (thread_local_.interrupt_flags_ != 0) {
set_limits(kInterruptLimit, access);
......@@ -271,9 +274,7 @@ bool StackGuard::IsInterrupted() {
void StackGuard::Interrupt() {
ExecutionAccess access;
thread_local_.interrupt_flags_ |= INTERRUPT;
if (!Top::is_break_no_lock()) {
set_limits(kInterruptLimit, access);
}
}
......@@ -286,9 +287,7 @@ bool StackGuard::IsPreempted() {
void StackGuard::Preempt() {
ExecutionAccess access;
thread_local_.interrupt_flags_ |= PREEMPT;
if (!Top::is_break_no_lock()) {
set_limits(kInterruptLimit, access);
}
}
......@@ -300,10 +299,8 @@ bool StackGuard::IsDebugBreak() {
void StackGuard::DebugBreak() {
ExecutionAccess access;
if (!Top::is_break_no_lock()) {
thread_local_.interrupt_flags_ |= DEBUGBREAK;
set_limits(kInterruptLimit, access);
}
}
......
......@@ -188,7 +188,7 @@ class StackGuard BASE_EMBEDDED {
static void EnableInterrupts();
static void DisableInterrupts();
static const int kLimitSize = 512 * KB;
static const uintptr_t kLimitSize = 512 * KB;
static const uintptr_t kInterruptLimit = 0xfffffffe;
static const uintptr_t kIllegalLimit = 0xffffffff;
......
......@@ -76,19 +76,7 @@ StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) {
void ExitFrame::Iterate(ObjectVisitor* v) const {
// Traverse pointers in the callee-saved registers.
const int offset = ExitFrameConstants::kSavedRegistersOffset;
Object** base = &Memory::Object_at(fp() + offset);
Object** limit = base + kNumJSCalleeSaved;
v->VisitPointers(base, limit);
}
void ExitFrame::RestoreCalleeSavedRegisters(Object* buffer[]) const {
// The callee-saved registers in an exit frame are pointed to by the
// frame pointer. See the implementations of C entry runtime stubs.
const int offset = ExitFrameConstants::kSavedRegistersOffset;
memcpy(buffer, fp() + offset, kNumJSCalleeSaved * kPointerSize);
// Do nothing
}
......@@ -119,58 +107,6 @@ Address InternalFrame::GetCallerStackPointer() const {
}
RegList JavaScriptFrame::FindCalleeSavedRegisters() const {
const unsigned kRegListTag = 1; // pc values have bit 0 cleared (no thumb)
const unsigned kRegListTagSize = 1;
const unsigned kRegListTagMask = (1 << kRegListTagSize) - 1;
// The prologue pc (or the cached register list) is available as a
// slot in the fixed part of the stack frame.
const int offset = +4 * kPointerSize;
// Once the register list has been calculated for a frame, it is
// cached in the prologue pc stack slot. Check the cache before
// doing the more expensive instruction decoding.
uint32_t cache = Memory::int_at(fp() + offset);
if ((cache & kRegListTagMask) == kRegListTag) {
return static_cast<RegList>(cache >> kRegListTagSize);
}
// If we can't find the register list in the instruction stream, we
// assume it's the empty list. [NOTE: Is this really a smart thing
// to do? Don't all JavaScript frames have the instruction?]
RegList result = 0;
// Compute the address of the stm (store multiple) instruction.
Address stm_address = AddressFrom<Address>(cache - PcStoreOffset());
ASSERT((Memory::int32_at(stm_address) & 0xffffcc00) == 0xe92dcc00);
// Fetch the instruction preceeding the stm - if it is also a stm
// instruction we read the register list from there.
uint32_t instruction = Memory::int32_at(stm_address - 4);
if ((instruction & 0xfffffc00) == 0xe92d0000) {
// The register list shouldn't be empty and must consist only of JS
// callee-saved registers.
result = instruction & 0xffff;
ASSERT(result != 0 && (result & ~kJSCalleeSaved) == 0);
}
// Cache the result in the prologue pc stack slot before returning
// it. This way future access to the register list is a bit faster.
Memory::int_at(fp() + offset) = (result << kRegListTagSize) | kRegListTag;
return result;
}
void JavaScriptFrame::RestoreCalleeSavedRegisters(Object* buffer[]) const {
// The callee-saved registers in java script frames are in the fixed
// part of the frame below the frame pointer.
const int n = NumRegs(FindCalleeSavedRegisters());
const int offset = 5 * kPointerSize;
memcpy(buffer, fp() + offset, n * kPointerSize);
}
Code* JavaScriptFrame::FindCode() const {
const int offset = StandardFrameConstants::kCodeOffset;
Object* code = Memory::Object_at(fp() + offset);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -103,11 +103,6 @@ inline StackHandler* StackFrame::top_handler() const {
}
inline Object** StackFrame::top_register_buffer() const {
return iterator_->register_buffer();
}
inline Object* StandardFrame::GetExpression(int index) const {
return Memory::Object_at(GetExpressionAddress(index));
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -179,7 +179,6 @@ class Top {
static void set_break(StackFrame::Id break_frame_id, int break_id);
static bool check_break(int break_id);
static bool is_break();
static bool is_break_no_lock();
static StackFrame::Id break_frame_id();
static int break_id();
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment