mirror of https://github.com/lukechilds/node.git
Ryan Dahl
15 years ago
150 changed files with 8072 additions and 6510 deletions
@ -0,0 +1,324 @@ |
|||||
|
# 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': Split(""" |
||||
|
accessors.cc |
||||
|
allocation.cc |
||||
|
api.cc |
||||
|
assembler.cc |
||||
|
ast.cc |
||||
|
bootstrapper.cc |
||||
|
builtins.cc |
||||
|
checks.cc |
||||
|
circular-queue.cc |
||||
|
code-stubs.cc |
||||
|
codegen.cc |
||||
|
compilation-cache.cc |
||||
|
compiler.cc |
||||
|
contexts.cc |
||||
|
conversions.cc |
||||
|
counters.cc |
||||
|
cpu-profiler.cc |
||||
|
data-flow.cc |
||||
|
dateparser.cc |
||||
|
debug-agent.cc |
||||
|
debug.cc |
||||
|
disassembler.cc |
||||
|
diy-fp.cc |
||||
|
dtoa.cc |
||||
|
execution.cc |
||||
|
factory.cc |
||||
|
flags.cc |
||||
|
flow-graph.cc |
||||
|
frame-element.cc |
||||
|
frames.cc |
||||
|
full-codegen.cc |
||||
|
func-name-inferrer.cc |
||||
|
global-handles.cc |
||||
|
fast-dtoa.cc |
||||
|
fixed-dtoa.cc |
||||
|
handles.cc |
||||
|
hashmap.cc |
||||
|
heap-profiler.cc |
||||
|
heap.cc |
||||
|
ic.cc |
||||
|
interpreter-irregexp.cc |
||||
|
jsregexp.cc |
||||
|
jump-target.cc |
||||
|
liveedit.cc |
||||
|
log-utils.cc |
||||
|
log.cc |
||||
|
mark-compact.cc |
||||
|
messages.cc |
||||
|
objects.cc |
||||
|
objects-visiting.cc |
||||
|
oprofile-agent.cc |
||||
|
parser.cc |
||||
|
profile-generator.cc |
||||
|
property.cc |
||||
|
regexp-macro-assembler-irregexp.cc |
||||
|
regexp-macro-assembler.cc |
||||
|
regexp-stack.cc |
||||
|
register-allocator.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 |
||||
|
type-info.cc |
||||
|
unicode.cc |
||||
|
utils.cc |
||||
|
v8-counters.cc |
||||
|
v8.cc |
||||
|
v8threads.cc |
||||
|
variables.cc |
||||
|
version.cc |
||||
|
virtual-frame.cc |
||||
|
vm-state.cc |
||||
|
zone.cc |
||||
|
"""), |
||||
|
'arch:arm': Split(""" |
||||
|
jump-target-light.cc |
||||
|
virtual-frame-light.cc |
||||
|
arm/builtins-arm.cc |
||||
|
arm/codegen-arm.cc |
||||
|
arm/constants-arm.cc |
||||
|
arm/cpu-arm.cc |
||||
|
arm/debug-arm.cc |
||||
|
arm/disasm-arm.cc |
||||
|
arm/frames-arm.cc |
||||
|
arm/full-codegen-arm.cc |
||||
|
arm/ic-arm.cc |
||||
|
arm/jump-target-arm.cc |
||||
|
arm/macro-assembler-arm.cc |
||||
|
arm/regexp-macro-assembler-arm.cc |
||||
|
arm/register-allocator-arm.cc |
||||
|
arm/stub-cache-arm.cc |
||||
|
arm/virtual-frame-arm.cc |
||||
|
arm/assembler-arm.cc |
||||
|
"""), |
||||
|
'arch:mips': Split(""" |
||||
|
mips/assembler-mips.cc |
||||
|
mips/builtins-mips.cc |
||||
|
mips/codegen-mips.cc |
||||
|
mips/constants-mips.cc |
||||
|
mips/cpu-mips.cc |
||||
|
mips/debug-mips.cc |
||||
|
mips/disasm-mips.cc |
||||
|
mips/full-codegen-mips.cc |
||||
|
mips/frames-mips.cc |
||||
|
mips/ic-mips.cc |
||||
|
mips/jump-target-mips.cc |
||||
|
mips/macro-assembler-mips.cc |
||||
|
mips/register-allocator-mips.cc |
||||
|
mips/stub-cache-mips.cc |
||||
|
mips/virtual-frame-mips.cc |
||||
|
"""), |
||||
|
'arch:ia32': Split(""" |
||||
|
jump-target-heavy.cc |
||||
|
virtual-frame-heavy.cc |
||||
|
ia32/assembler-ia32.cc |
||||
|
ia32/builtins-ia32.cc |
||||
|
ia32/codegen-ia32.cc |
||||
|
ia32/cpu-ia32.cc |
||||
|
ia32/debug-ia32.cc |
||||
|
ia32/disasm-ia32.cc |
||||
|
ia32/frames-ia32.cc |
||||
|
ia32/full-codegen-ia32.cc |
||||
|
ia32/ic-ia32.cc |
||||
|
ia32/jump-target-ia32.cc |
||||
|
ia32/macro-assembler-ia32.cc |
||||
|
ia32/regexp-macro-assembler-ia32.cc |
||||
|
ia32/register-allocator-ia32.cc |
||||
|
ia32/stub-cache-ia32.cc |
||||
|
ia32/virtual-frame-ia32.cc |
||||
|
"""), |
||||
|
'arch:x64': Split(""" |
||||
|
jump-target-heavy.cc |
||||
|
virtual-frame-heavy.cc |
||||
|
x64/assembler-x64.cc |
||||
|
x64/builtins-x64.cc |
||||
|
x64/codegen-x64.cc |
||||
|
x64/cpu-x64.cc |
||||
|
x64/debug-x64.cc |
||||
|
x64/disasm-x64.cc |
||||
|
x64/frames-x64.cc |
||||
|
x64/full-codegen-x64.cc |
||||
|
x64/ic-x64.cc |
||||
|
x64/jump-target-x64.cc |
||||
|
x64/macro-assembler-x64.cc |
||||
|
x64/regexp-macro-assembler-x64.cc |
||||
|
x64/register-allocator-x64.cc |
||||
|
x64/stub-cache-x64.cc |
||||
|
x64/virtual-frame-x64.cc |
||||
|
"""), |
||||
|
'simulator:arm': ['arm/simulator-arm.cc'], |
||||
|
'simulator:mips': ['mips/simulator-mips.cc'], |
||||
|
'os:freebsd': ['platform-freebsd.cc', 'platform-posix.cc'], |
||||
|
'os:openbsd': ['platform-openbsd.cc', 'platform-posix.cc'], |
||||
|
'os:linux': ['platform-linux.cc', 'platform-posix.cc'], |
||||
|
'os:android': ['platform-linux.cc', 'platform-posix.cc'], |
||||
|
'os:macos': ['platform-macos.cc', 'platform-posix.cc'], |
||||
|
'os:solaris': ['platform-solaris.cc', 'platform-posix.cc'], |
||||
|
'os:nullos': ['platform-nullos.cc'], |
||||
|
'os:win32': ['platform-win32.cc'], |
||||
|
'mode:release': [], |
||||
|
'mode:debug': [ |
||||
|
'objects-debug.cc', 'prettyprinter.cc', 'regexp-macro-assembler-tracer.cc' |
||||
|
] |
||||
|
} |
||||
|
|
||||
|
|
||||
|
D8_FILES = { |
||||
|
'all': [ |
||||
|
'd8.cc', 'd8-debug.cc' |
||||
|
], |
||||
|
'os:linux': [ |
||||
|
'd8-posix.cc' |
||||
|
], |
||||
|
'os:macos': [ |
||||
|
'd8-posix.cc' |
||||
|
], |
||||
|
'os:android': [ |
||||
|
'd8-posix.cc' |
||||
|
], |
||||
|
'os:freebsd': [ |
||||
|
'd8-posix.cc' |
||||
|
], |
||||
|
'os:openbsd': [ |
||||
|
'd8-posix.cc' |
||||
|
], |
||||
|
'os:solaris': [ |
||||
|
'd8-posix.cc' |
||||
|
], |
||||
|
'os:win32': [ |
||||
|
'd8-windows.cc' |
||||
|
], |
||||
|
'os:nullos': [ |
||||
|
'd8-windows.cc' # Empty implementation at the moment. |
||||
|
], |
||||
|
'console:readline': [ |
||||
|
'd8-readline.cc' |
||||
|
] |
||||
|
} |
||||
|
|
||||
|
|
||||
|
LIBRARY_FILES = ''' |
||||
|
runtime.js |
||||
|
v8natives.js |
||||
|
array.js |
||||
|
string.js |
||||
|
uri.js |
||||
|
math.js |
||||
|
messages.js |
||||
|
apinatives.js |
||||
|
date.js |
||||
|
regexp.js |
||||
|
json.js |
||||
|
liveedit-debugger.js |
||||
|
mirror-debugger.js |
||||
|
debug-debugger.js |
||||
|
'''.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" --log-snapshot-positions') |
||||
|
|
||||
|
# 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 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 = [dtoa_obj, source_objs] |
||||
|
|
||||
|
# Create snapshot if necessary. For cross compilation you should either |
||||
|
# do without snapshots and take the performance hit or you should build a |
||||
|
# host VM with the simulator=arm and snapshot=on options and then take the |
||||
|
# resulting snapshot.cc file from obj/release and put it in the src |
||||
|
# directory. Then rebuild the VM with the cross compiler and specify |
||||
|
# snapshot=nobuild on the scons command line. |
||||
|
empty_snapshot_obj = context.ConfigureObject(env, 'snapshot-empty.cc') |
||||
|
mksnapshot_env = env.Copy() |
||||
|
mksnapshot_env.Replace(**context.flags['mksnapshot']) |
||||
|
mksnapshot_src = 'mksnapshot.cc' |
||||
|
mksnapshot = mksnapshot_env.Program('mksnapshot', [mksnapshot_src, libraries_obj, non_snapshot_files, empty_snapshot_obj], PDB='mksnapshot.exe.pdb') |
||||
|
if context.use_snapshot: |
||||
|
if context.build_snapshot: |
||||
|
snapshot_cc = env.Snapshot('snapshot.cc', mksnapshot, LOGFILE=File('snapshot.log').abspath) |
||||
|
else: |
||||
|
snapshot_cc = 'snapshot.cc' |
||||
|
snapshot_obj = context.ConfigureObject(env, snapshot_cc, CPPPATH=['.']) |
||||
|
else: |
||||
|
snapshot_obj = empty_snapshot_obj |
||||
|
library_objs = [non_snapshot_files, libraries_obj, snapshot_obj] |
||||
|
return (library_objs, d8_objs, [mksnapshot]) |
||||
|
|
||||
|
|
||||
|
(library_objs, d8_objs, mksnapshot) = ConfigureObjectFiles() |
||||
|
Return('library_objs d8_objs mksnapshot') |
File diff suppressed because it is too large
@ -1,241 +0,0 @@ |
|||||
// Copyright 2010 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" |
|
||||
|
|
||||
#if defined(V8_TARGET_ARCH_ARM) |
|
||||
|
|
||||
#include "codegen-inl.h" |
|
||||
#include "fast-codegen.h" |
|
||||
#include "scopes.h" |
|
||||
|
|
||||
namespace v8 { |
|
||||
namespace internal { |
|
||||
|
|
||||
#define __ ACCESS_MASM(masm()) |
|
||||
|
|
||||
Register FastCodeGenerator::accumulator0() { return r0; } |
|
||||
Register FastCodeGenerator::accumulator1() { return r1; } |
|
||||
Register FastCodeGenerator::scratch0() { return r3; } |
|
||||
Register FastCodeGenerator::scratch1() { return r4; } |
|
||||
Register FastCodeGenerator::scratch2() { return r5; } |
|
||||
Register FastCodeGenerator::receiver_reg() { return r2; } |
|
||||
Register FastCodeGenerator::context_reg() { return cp; } |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::EmitLoadReceiver() { |
|
||||
// Offset 2 is due to return address and saved frame pointer.
|
|
||||
int index = 2 + scope()->num_parameters(); |
|
||||
__ ldr(receiver_reg(), MemOperand(sp, index * kPointerSize)); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::EmitGlobalVariableLoad(Handle<Object> cell) { |
|
||||
ASSERT(!destination().is(no_reg)); |
|
||||
ASSERT(cell->IsJSGlobalPropertyCell()); |
|
||||
|
|
||||
__ mov(destination(), Operand(cell)); |
|
||||
__ ldr(destination(), |
|
||||
FieldMemOperand(destination(), JSGlobalPropertyCell::kValueOffset)); |
|
||||
if (FLAG_debug_code) { |
|
||||
__ mov(ip, Operand(Factory::the_hole_value())); |
|
||||
__ cmp(destination(), ip); |
|
||||
__ Check(ne, "DontDelete cells can't contain the hole"); |
|
||||
} |
|
||||
|
|
||||
// The loaded value is not known to be a smi.
|
|
||||
clear_as_smi(destination()); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::EmitThisPropertyStore(Handle<String> name) { |
|
||||
LookupResult lookup; |
|
||||
info()->receiver()->Lookup(*name, &lookup); |
|
||||
|
|
||||
ASSERT(lookup.holder() == *info()->receiver()); |
|
||||
ASSERT(lookup.type() == FIELD); |
|
||||
Handle<Map> map(Handle<HeapObject>::cast(info()->receiver())->map()); |
|
||||
int index = lookup.GetFieldIndex() - map->inobject_properties(); |
|
||||
int offset = index * kPointerSize; |
|
||||
|
|
||||
// We will emit the write barrier unless the stored value is statically
|
|
||||
// known to be a smi.
|
|
||||
bool needs_write_barrier = !is_smi(accumulator0()); |
|
||||
|
|
||||
// Negative offsets are inobject properties.
|
|
||||
if (offset < 0) { |
|
||||
offset += map->instance_size(); |
|
||||
__ str(accumulator0(), FieldMemOperand(receiver_reg(), offset)); |
|
||||
if (needs_write_barrier) { |
|
||||
// Preserve receiver from write barrier.
|
|
||||
__ mov(scratch0(), receiver_reg()); |
|
||||
} |
|
||||
} else { |
|
||||
offset += FixedArray::kHeaderSize; |
|
||||
__ ldr(scratch0(), |
|
||||
FieldMemOperand(receiver_reg(), JSObject::kPropertiesOffset)); |
|
||||
__ str(accumulator0(), FieldMemOperand(scratch0(), offset)); |
|
||||
} |
|
||||
|
|
||||
if (needs_write_barrier) { |
|
||||
__ RecordWrite(scratch0(), Operand(offset), scratch1(), scratch2()); |
|
||||
} |
|
||||
|
|
||||
if (destination().is(accumulator1())) { |
|
||||
__ mov(accumulator1(), accumulator0()); |
|
||||
if (is_smi(accumulator0())) { |
|
||||
set_as_smi(accumulator1()); |
|
||||
} else { |
|
||||
clear_as_smi(accumulator1()); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::EmitThisPropertyLoad(Handle<String> name) { |
|
||||
ASSERT(!destination().is(no_reg)); |
|
||||
LookupResult lookup; |
|
||||
info()->receiver()->Lookup(*name, &lookup); |
|
||||
|
|
||||
ASSERT(lookup.holder() == *info()->receiver()); |
|
||||
ASSERT(lookup.type() == FIELD); |
|
||||
Handle<Map> map(Handle<HeapObject>::cast(info()->receiver())->map()); |
|
||||
int index = lookup.GetFieldIndex() - map->inobject_properties(); |
|
||||
int offset = index * kPointerSize; |
|
||||
|
|
||||
// Perform the load. Negative offsets are inobject properties.
|
|
||||
if (offset < 0) { |
|
||||
offset += map->instance_size(); |
|
||||
__ ldr(destination(), FieldMemOperand(receiver_reg(), offset)); |
|
||||
} else { |
|
||||
offset += FixedArray::kHeaderSize; |
|
||||
__ ldr(scratch0(), |
|
||||
FieldMemOperand(receiver_reg(), JSObject::kPropertiesOffset)); |
|
||||
__ ldr(destination(), FieldMemOperand(scratch0(), offset)); |
|
||||
} |
|
||||
|
|
||||
// The loaded value is not known to be a smi.
|
|
||||
clear_as_smi(destination()); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::EmitBitOr() { |
|
||||
if (is_smi(accumulator0()) && is_smi(accumulator1())) { |
|
||||
// If both operands are known to be a smi then there is no need to check
|
|
||||
// the operands or result. There is no need to perform the operation in
|
|
||||
// an effect context.
|
|
||||
if (!destination().is(no_reg)) { |
|
||||
__ orr(destination(), accumulator1(), Operand(accumulator0())); |
|
||||
} |
|
||||
} else { |
|
||||
// Left is in accumulator1, right in accumulator0.
|
|
||||
if (destination().is(accumulator0())) { |
|
||||
__ mov(scratch0(), accumulator0()); |
|
||||
__ orr(destination(), accumulator1(), Operand(accumulator1())); |
|
||||
Label* bailout = |
|
||||
info()->AddBailout(accumulator1(), scratch0()); // Left, right.
|
|
||||
__ BranchOnNotSmi(destination(), bailout); |
|
||||
} else if (destination().is(accumulator1())) { |
|
||||
__ mov(scratch0(), accumulator1()); |
|
||||
__ orr(destination(), accumulator1(), Operand(accumulator0())); |
|
||||
Label* bailout = info()->AddBailout(scratch0(), accumulator0()); |
|
||||
__ BranchOnNotSmi(destination(), bailout); |
|
||||
} else { |
|
||||
ASSERT(destination().is(no_reg)); |
|
||||
__ orr(scratch0(), accumulator1(), Operand(accumulator0())); |
|
||||
Label* bailout = info()->AddBailout(accumulator1(), accumulator0()); |
|
||||
__ BranchOnNotSmi(scratch0(), bailout); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// If we didn't bailout, the result (in fact, both inputs too) is known to
|
|
||||
// be a smi.
|
|
||||
set_as_smi(accumulator0()); |
|
||||
set_as_smi(accumulator1()); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::Generate(CompilationInfo* compilation_info) { |
|
||||
ASSERT(info_ == NULL); |
|
||||
info_ = compilation_info; |
|
||||
Comment cmnt(masm_, "[ function compiled by fast code generator"); |
|
||||
|
|
||||
// Save the caller's frame pointer and set up our own.
|
|
||||
Comment prologue_cmnt(masm(), ";; Prologue"); |
|
||||
__ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); |
|
||||
__ add(fp, sp, Operand(2 * kPointerSize)); |
|
||||
// Note that we keep a live register reference to cp (context) at
|
|
||||
// this point.
|
|
||||
|
|
||||
Label* bailout_to_beginning = info()->AddBailout(); |
|
||||
// Receiver (this) is allocated to a fixed register.
|
|
||||
if (info()->has_this_properties()) { |
|
||||
Comment cmnt(masm(), ";; MapCheck(this)"); |
|
||||
if (FLAG_print_ir) { |
|
||||
PrintF("MapCheck(this)\n"); |
|
||||
} |
|
||||
ASSERT(info()->has_receiver() && info()->receiver()->IsHeapObject()); |
|
||||
Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver()); |
|
||||
Handle<Map> map(object->map()); |
|
||||
EmitLoadReceiver(); |
|
||||
__ CheckMap(receiver_reg(), scratch0(), map, bailout_to_beginning, false); |
|
||||
} |
|
||||
|
|
||||
// If there is a global variable access check if the global object is the
|
|
||||
// same as at lazy-compilation time.
|
|
||||
if (info()->has_globals()) { |
|
||||
Comment cmnt(masm(), ";; MapCheck(GLOBAL)"); |
|
||||
if (FLAG_print_ir) { |
|
||||
PrintF("MapCheck(GLOBAL)\n"); |
|
||||
} |
|
||||
ASSERT(info()->has_global_object()); |
|
||||
Handle<Map> map(info()->global_object()->map()); |
|
||||
__ ldr(scratch0(), CodeGenerator::GlobalObject()); |
|
||||
__ CheckMap(scratch0(), scratch1(), map, bailout_to_beginning, true); |
|
||||
} |
|
||||
|
|
||||
VisitStatements(function()->body()); |
|
||||
|
|
||||
Comment return_cmnt(masm(), ";; Return(<undefined>)"); |
|
||||
if (FLAG_print_ir) { |
|
||||
PrintF("Return(<undefined>)\n"); |
|
||||
} |
|
||||
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex); |
|
||||
__ mov(sp, fp); |
|
||||
__ ldm(ia_w, sp, fp.bit() | lr.bit()); |
|
||||
int32_t sp_delta = (scope()->num_parameters() + 1) * kPointerSize; |
|
||||
__ add(sp, sp, Operand(sp_delta)); |
|
||||
__ Jump(lr); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
#undef __ |
|
||||
|
|
||||
|
|
||||
} } // namespace v8::internal
|
|
||||
|
|
||||
#endif // V8_TARGET_ARCH_ARM
|
|
@ -1,746 +0,0 @@ |
|||||
// Copyright 2010 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 "data-flow.h" |
|
||||
#include "fast-codegen.h" |
|
||||
#include "scopes.h" |
|
||||
|
|
||||
namespace v8 { |
|
||||
namespace internal { |
|
||||
|
|
||||
#define BAILOUT(reason) \ |
|
||||
do { \ |
|
||||
if (FLAG_trace_bailout) { \ |
|
||||
PrintF("%s\n", reason); \ |
|
||||
} \ |
|
||||
has_supported_syntax_ = false; \ |
|
||||
return; \ |
|
||||
} while (false) |
|
||||
|
|
||||
|
|
||||
#define CHECK_BAILOUT \ |
|
||||
do { \ |
|
||||
if (!has_supported_syntax_) return; \ |
|
||||
} while (false) |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::Check(CompilationInfo* info) { |
|
||||
info_ = info; |
|
||||
|
|
||||
// We do not specialize if we do not have a receiver or if it is not a
|
|
||||
// JS object with fast mode properties.
|
|
||||
if (!info->has_receiver()) BAILOUT("No receiver"); |
|
||||
if (!info->receiver()->IsJSObject()) BAILOUT("Receiver is not an object"); |
|
||||
Handle<JSObject> object = Handle<JSObject>::cast(info->receiver()); |
|
||||
if (!object->HasFastProperties()) BAILOUT("Receiver is in dictionary mode"); |
|
||||
|
|
||||
// We do not support stack or heap slots (both of which require
|
|
||||
// allocation).
|
|
||||
Scope* scope = info->scope(); |
|
||||
if (scope->num_stack_slots() > 0) { |
|
||||
BAILOUT("Function has stack-allocated locals"); |
|
||||
} |
|
||||
if (scope->num_heap_slots() > 0) { |
|
||||
BAILOUT("Function has context-allocated locals"); |
|
||||
} |
|
||||
|
|
||||
VisitDeclarations(scope->declarations()); |
|
||||
CHECK_BAILOUT; |
|
||||
|
|
||||
// We do not support empty function bodies.
|
|
||||
if (info->function()->body()->is_empty()) { |
|
||||
BAILOUT("Function has an empty body"); |
|
||||
} |
|
||||
VisitStatements(info->function()->body()); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitDeclarations( |
|
||||
ZoneList<Declaration*>* decls) { |
|
||||
if (!decls->is_empty()) BAILOUT("Function has declarations"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitStatements(ZoneList<Statement*>* stmts) { |
|
||||
if (stmts->length() != 1) { |
|
||||
BAILOUT("Function body is not a singleton statement."); |
|
||||
} |
|
||||
Visit(stmts->at(0)); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitDeclaration(Declaration* decl) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitBlock(Block* stmt) { |
|
||||
VisitStatements(stmt->statements()); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitExpressionStatement( |
|
||||
ExpressionStatement* stmt) { |
|
||||
Visit(stmt->expression()); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitEmptyStatement(EmptyStatement* stmt) { |
|
||||
// Supported.
|
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitIfStatement(IfStatement* stmt) { |
|
||||
BAILOUT("IfStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitContinueStatement(ContinueStatement* stmt) { |
|
||||
BAILOUT("Continuestatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitBreakStatement(BreakStatement* stmt) { |
|
||||
BAILOUT("BreakStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitReturnStatement(ReturnStatement* stmt) { |
|
||||
BAILOUT("ReturnStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitWithEnterStatement( |
|
||||
WithEnterStatement* stmt) { |
|
||||
BAILOUT("WithEnterStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitWithExitStatement(WithExitStatement* stmt) { |
|
||||
BAILOUT("WithExitStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitSwitchStatement(SwitchStatement* stmt) { |
|
||||
BAILOUT("SwitchStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitDoWhileStatement(DoWhileStatement* stmt) { |
|
||||
BAILOUT("DoWhileStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitWhileStatement(WhileStatement* stmt) { |
|
||||
BAILOUT("WhileStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitForStatement(ForStatement* stmt) { |
|
||||
BAILOUT("ForStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitForInStatement(ForInStatement* stmt) { |
|
||||
BAILOUT("ForInStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitTryCatchStatement(TryCatchStatement* stmt) { |
|
||||
BAILOUT("TryCatchStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitTryFinallyStatement( |
|
||||
TryFinallyStatement* stmt) { |
|
||||
BAILOUT("TryFinallyStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitDebuggerStatement( |
|
||||
DebuggerStatement* stmt) { |
|
||||
BAILOUT("DebuggerStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitFunctionLiteral(FunctionLiteral* expr) { |
|
||||
BAILOUT("FunctionLiteral"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitSharedFunctionInfoLiteral( |
|
||||
SharedFunctionInfoLiteral* expr) { |
|
||||
BAILOUT("SharedFunctionInfoLiteral"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitConditional(Conditional* expr) { |
|
||||
BAILOUT("Conditional"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitSlot(Slot* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitVariableProxy(VariableProxy* expr) { |
|
||||
// Only global variable references are supported.
|
|
||||
Variable* var = expr->var(); |
|
||||
if (!var->is_global() || var->is_this()) BAILOUT("Non-global variable"); |
|
||||
|
|
||||
// Check if the global variable is existing and non-deletable.
|
|
||||
if (info()->has_global_object()) { |
|
||||
LookupResult lookup; |
|
||||
info()->global_object()->Lookup(*expr->name(), &lookup); |
|
||||
if (!lookup.IsProperty()) { |
|
||||
BAILOUT("Non-existing global variable"); |
|
||||
} |
|
||||
// We do not handle global variables with accessors or interceptors.
|
|
||||
if (lookup.type() != NORMAL) { |
|
||||
BAILOUT("Global variable with accessors or interceptors."); |
|
||||
} |
|
||||
// We do not handle deletable global variables.
|
|
||||
if (!lookup.IsDontDelete()) { |
|
||||
BAILOUT("Deletable global variable"); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitLiteral(Literal* expr) { |
|
||||
BAILOUT("Literal"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitRegExpLiteral(RegExpLiteral* expr) { |
|
||||
BAILOUT("RegExpLiteral"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitObjectLiteral(ObjectLiteral* expr) { |
|
||||
BAILOUT("ObjectLiteral"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitArrayLiteral(ArrayLiteral* expr) { |
|
||||
BAILOUT("ArrayLiteral"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitCatchExtensionObject( |
|
||||
CatchExtensionObject* expr) { |
|
||||
BAILOUT("CatchExtensionObject"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitAssignment(Assignment* expr) { |
|
||||
// Simple assignments to (named) this properties are supported.
|
|
||||
if (expr->op() != Token::ASSIGN) BAILOUT("Non-simple assignment"); |
|
||||
|
|
||||
Property* prop = expr->target()->AsProperty(); |
|
||||
if (prop == NULL) BAILOUT("Non-property assignment"); |
|
||||
VariableProxy* proxy = prop->obj()->AsVariableProxy(); |
|
||||
if (proxy == NULL || !proxy->var()->is_this()) { |
|
||||
BAILOUT("Non-this-property assignment"); |
|
||||
} |
|
||||
if (!prop->key()->IsPropertyName()) { |
|
||||
BAILOUT("Non-named-property assignment"); |
|
||||
} |
|
||||
|
|
||||
// We will only specialize for fields on the object itself.
|
|
||||
// Expression::IsPropertyName implies that the name is a literal
|
|
||||
// symbol but we do not assume that.
|
|
||||
Literal* key = prop->key()->AsLiteral(); |
|
||||
if (key != NULL && key->handle()->IsString()) { |
|
||||
Handle<Object> receiver = info()->receiver(); |
|
||||
Handle<String> name = Handle<String>::cast(key->handle()); |
|
||||
LookupResult lookup; |
|
||||
receiver->Lookup(*name, &lookup); |
|
||||
if (!lookup.IsProperty()) { |
|
||||
BAILOUT("Assigned property not found at compile time"); |
|
||||
} |
|
||||
if (lookup.holder() != *receiver) BAILOUT("Non-own property assignment"); |
|
||||
if (!lookup.type() == FIELD) BAILOUT("Non-field property assignment"); |
|
||||
} else { |
|
||||
UNREACHABLE(); |
|
||||
BAILOUT("Unexpected non-string-literal property key"); |
|
||||
} |
|
||||
|
|
||||
Visit(expr->value()); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitThrow(Throw* expr) { |
|
||||
BAILOUT("Throw"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitProperty(Property* expr) { |
|
||||
// We support named this property references.
|
|
||||
VariableProxy* proxy = expr->obj()->AsVariableProxy(); |
|
||||
if (proxy == NULL || !proxy->var()->is_this()) { |
|
||||
BAILOUT("Non-this-property reference"); |
|
||||
} |
|
||||
if (!expr->key()->IsPropertyName()) { |
|
||||
BAILOUT("Non-named-property reference"); |
|
||||
} |
|
||||
|
|
||||
// We will only specialize for fields on the object itself.
|
|
||||
// Expression::IsPropertyName implies that the name is a literal
|
|
||||
// symbol but we do not assume that.
|
|
||||
Literal* key = expr->key()->AsLiteral(); |
|
||||
if (key != NULL && key->handle()->IsString()) { |
|
||||
Handle<Object> receiver = info()->receiver(); |
|
||||
Handle<String> name = Handle<String>::cast(key->handle()); |
|
||||
LookupResult lookup; |
|
||||
receiver->Lookup(*name, &lookup); |
|
||||
if (!lookup.IsProperty()) { |
|
||||
BAILOUT("Referenced property not found at compile time"); |
|
||||
} |
|
||||
if (lookup.holder() != *receiver) BAILOUT("Non-own property reference"); |
|
||||
if (!lookup.type() == FIELD) BAILOUT("Non-field property reference"); |
|
||||
} else { |
|
||||
UNREACHABLE(); |
|
||||
BAILOUT("Unexpected non-string-literal property key"); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitCall(Call* expr) { |
|
||||
BAILOUT("Call"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitCallNew(CallNew* expr) { |
|
||||
BAILOUT("CallNew"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitCallRuntime(CallRuntime* expr) { |
|
||||
BAILOUT("CallRuntime"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitUnaryOperation(UnaryOperation* expr) { |
|
||||
BAILOUT("UnaryOperation"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitCountOperation(CountOperation* expr) { |
|
||||
BAILOUT("CountOperation"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitBinaryOperation(BinaryOperation* expr) { |
|
||||
// We support bitwise OR.
|
|
||||
switch (expr->op()) { |
|
||||
case Token::COMMA: |
|
||||
BAILOUT("BinaryOperation COMMA"); |
|
||||
case Token::OR: |
|
||||
BAILOUT("BinaryOperation OR"); |
|
||||
case Token::AND: |
|
||||
BAILOUT("BinaryOperation AND"); |
|
||||
|
|
||||
case Token::BIT_OR: |
|
||||
// We support expressions nested on the left because they only require
|
|
||||
// a pair of registers to keep all intermediate values in registers
|
|
||||
// (i.e., the expression stack has height no more than two).
|
|
||||
if (!expr->right()->IsLeaf()) BAILOUT("expression nested on right"); |
|
||||
|
|
||||
// We do not allow subexpressions with side effects because we
|
|
||||
// (currently) bail out to the beginning of the full function. The
|
|
||||
// only expressions with side effects that we would otherwise handle
|
|
||||
// are assignments.
|
|
||||
if (expr->left()->AsAssignment() != NULL || |
|
||||
expr->right()->AsAssignment() != NULL) { |
|
||||
BAILOUT("subexpression of binary operation has side effects"); |
|
||||
} |
|
||||
|
|
||||
Visit(expr->left()); |
|
||||
CHECK_BAILOUT; |
|
||||
Visit(expr->right()); |
|
||||
break; |
|
||||
|
|
||||
case Token::BIT_XOR: |
|
||||
BAILOUT("BinaryOperation BIT_XOR"); |
|
||||
case Token::BIT_AND: |
|
||||
BAILOUT("BinaryOperation BIT_AND"); |
|
||||
case Token::SHL: |
|
||||
BAILOUT("BinaryOperation SHL"); |
|
||||
case Token::SAR: |
|
||||
BAILOUT("BinaryOperation SAR"); |
|
||||
case Token::SHR: |
|
||||
BAILOUT("BinaryOperation SHR"); |
|
||||
case Token::ADD: |
|
||||
BAILOUT("BinaryOperation ADD"); |
|
||||
case Token::SUB: |
|
||||
BAILOUT("BinaryOperation SUB"); |
|
||||
case Token::MUL: |
|
||||
BAILOUT("BinaryOperation MUL"); |
|
||||
case Token::DIV: |
|
||||
BAILOUT("BinaryOperation DIV"); |
|
||||
case Token::MOD: |
|
||||
BAILOUT("BinaryOperation MOD"); |
|
||||
default: |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitCompareOperation(CompareOperation* expr) { |
|
||||
BAILOUT("CompareOperation"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitThisFunction(ThisFunction* expr) { |
|
||||
BAILOUT("ThisFunction"); |
|
||||
} |
|
||||
|
|
||||
#undef BAILOUT |
|
||||
#undef CHECK_BAILOUT |
|
||||
|
|
||||
|
|
||||
#define __ ACCESS_MASM(masm()) |
|
||||
|
|
||||
Handle<Code> FastCodeGenerator::MakeCode(CompilationInfo* info) { |
|
||||
// Label the AST before calling MakeCodePrologue, so AST node numbers are
|
|
||||
// printed with the AST.
|
|
||||
AstLabeler labeler; |
|
||||
labeler.Label(info); |
|
||||
|
|
||||
CodeGenerator::MakeCodePrologue(info); |
|
||||
|
|
||||
const int kInitialBufferSize = 4 * KB; |
|
||||
MacroAssembler masm(NULL, kInitialBufferSize); |
|
||||
|
|
||||
// Generate the fast-path code.
|
|
||||
FastCodeGenerator fast_cgen(&masm); |
|
||||
fast_cgen.Generate(info); |
|
||||
if (fast_cgen.HasStackOverflow()) { |
|
||||
ASSERT(!Top::has_pending_exception()); |
|
||||
return Handle<Code>::null(); |
|
||||
} |
|
||||
|
|
||||
// Generate the full code for the function in bailout mode, using the same
|
|
||||
// macro assembler.
|
|
||||
CodeGenerator cgen(&masm); |
|
||||
CodeGeneratorScope scope(&cgen); |
|
||||
info->set_mode(CompilationInfo::SECONDARY); |
|
||||
cgen.Generate(info); |
|
||||
if (cgen.HasStackOverflow()) { |
|
||||
ASSERT(!Top::has_pending_exception()); |
|
||||
return Handle<Code>::null(); |
|
||||
} |
|
||||
|
|
||||
Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, NOT_IN_LOOP); |
|
||||
return CodeGenerator::MakeCodeEpilogue(&masm, flags, info); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitDeclaration(Declaration* decl) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitBlock(Block* stmt) { |
|
||||
VisitStatements(stmt->statements()); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { |
|
||||
Visit(stmt->expression()); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) { |
|
||||
// Nothing to do.
|
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitIfStatement(IfStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitBreakStatement(BreakStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitWithEnterStatement(WithEnterStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitWithExitStatement(WithExitStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitWhileStatement(WhileStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitForStatement(ForStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitSharedFunctionInfoLiteral( |
|
||||
SharedFunctionInfoLiteral* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitConditional(Conditional* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitSlot(Slot* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { |
|
||||
ASSERT(expr->var()->is_global() && !expr->var()->is_this()); |
|
||||
// Check if we can compile a global variable load directly from the cell.
|
|
||||
ASSERT(info()->has_global_object()); |
|
||||
LookupResult lookup; |
|
||||
info()->global_object()->Lookup(*expr->name(), &lookup); |
|
||||
// We only support normal (non-accessor/interceptor) DontDelete properties
|
|
||||
// for now.
|
|
||||
ASSERT(lookup.IsProperty()); |
|
||||
ASSERT_EQ(NORMAL, lookup.type()); |
|
||||
ASSERT(lookup.IsDontDelete()); |
|
||||
Handle<Object> cell(info()->global_object()->GetPropertyCell(&lookup)); |
|
||||
|
|
||||
// Global variable lookups do not have side effects, so we do not need to
|
|
||||
// emit code if we are in an effect context.
|
|
||||
if (!destination().is(no_reg)) { |
|
||||
Comment cmnt(masm(), ";; Global"); |
|
||||
if (FLAG_print_ir) { |
|
||||
SmartPointer<char> name = expr->name()->ToCString(); |
|
||||
PrintF("%d: t%d = Global(%s)\n", expr->num(), |
|
||||
expr->num(), *name); |
|
||||
} |
|
||||
EmitGlobalVariableLoad(cell); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitLiteral(Literal* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitAssignment(Assignment* expr) { |
|
||||
// Known to be a simple this property assignment. Effectively a unary
|
|
||||
// operation.
|
|
||||
{ Register my_destination = destination(); |
|
||||
set_destination(accumulator0()); |
|
||||
Visit(expr->value()); |
|
||||
set_destination(my_destination); |
|
||||
} |
|
||||
|
|
||||
Property* prop = expr->target()->AsProperty(); |
|
||||
ASSERT_NOT_NULL(prop); |
|
||||
ASSERT_NOT_NULL(prop->obj()->AsVariableProxy()); |
|
||||
ASSERT(prop->obj()->AsVariableProxy()->var()->is_this()); |
|
||||
ASSERT(prop->key()->IsPropertyName()); |
|
||||
Handle<String> name = |
|
||||
Handle<String>::cast(prop->key()->AsLiteral()->handle()); |
|
||||
|
|
||||
Comment cmnt(masm(), ";; Store to this"); |
|
||||
if (FLAG_print_ir) { |
|
||||
SmartPointer<char> name_string = name->ToCString(); |
|
||||
PrintF("%d: ", expr->num()); |
|
||||
if (!destination().is(no_reg)) PrintF("t%d = ", expr->num()); |
|
||||
PrintF("Store(this, \"%s\", t%d)\n", *name_string, |
|
||||
expr->value()->num()); |
|
||||
} |
|
||||
|
|
||||
EmitThisPropertyStore(name); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitThrow(Throw* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitProperty(Property* expr) { |
|
||||
ASSERT_NOT_NULL(expr->obj()->AsVariableProxy()); |
|
||||
ASSERT(expr->obj()->AsVariableProxy()->var()->is_this()); |
|
||||
ASSERT(expr->key()->IsPropertyName()); |
|
||||
if (!destination().is(no_reg)) { |
|
||||
Handle<String> name = |
|
||||
Handle<String>::cast(expr->key()->AsLiteral()->handle()); |
|
||||
|
|
||||
Comment cmnt(masm(), ";; Load from this"); |
|
||||
if (FLAG_print_ir) { |
|
||||
SmartPointer<char> name_string = name->ToCString(); |
|
||||
PrintF("%d: t%d = Load(this, \"%s\")\n", |
|
||||
expr->num(), expr->num(), *name_string); |
|
||||
} |
|
||||
EmitThisPropertyLoad(name); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitCall(Call* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitCallNew(CallNew* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitCountOperation(CountOperation* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { |
|
||||
// We support limited binary operations: bitwise OR only allowed to be
|
|
||||
// nested on the left.
|
|
||||
ASSERT(expr->op() == Token::BIT_OR); |
|
||||
ASSERT(expr->right()->IsLeaf()); |
|
||||
|
|
||||
{ Register my_destination = destination(); |
|
||||
set_destination(accumulator1()); |
|
||||
Visit(expr->left()); |
|
||||
set_destination(accumulator0()); |
|
||||
Visit(expr->right()); |
|
||||
set_destination(my_destination); |
|
||||
} |
|
||||
|
|
||||
Comment cmnt(masm(), ";; BIT_OR"); |
|
||||
if (FLAG_print_ir) { |
|
||||
PrintF("%d: ", expr->num()); |
|
||||
if (!destination().is(no_reg)) PrintF("t%d = ", expr->num()); |
|
||||
PrintF("BIT_OR(t%d, t%d)\n", expr->left()->num(), expr->right()->num()); |
|
||||
} |
|
||||
EmitBitOr(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
#undef __ |
|
||||
|
|
||||
|
|
||||
} } // namespace v8::internal
|
|
@ -1,161 +0,0 @@ |
|||||
// Copyright 2010 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_FAST_CODEGEN_H_ |
|
||||
#define V8_FAST_CODEGEN_H_ |
|
||||
|
|
||||
#if V8_TARGET_ARCH_IA32 |
|
||||
#include "ia32/fast-codegen-ia32.h" |
|
||||
#else |
|
||||
|
|
||||
#include "v8.h" |
|
||||
|
|
||||
#include "ast.h" |
|
||||
#include "compiler.h" |
|
||||
#include "list.h" |
|
||||
|
|
||||
namespace v8 { |
|
||||
namespace internal { |
|
||||
|
|
||||
class FastCodeGenSyntaxChecker: public AstVisitor { |
|
||||
public: |
|
||||
explicit FastCodeGenSyntaxChecker() |
|
||||
: info_(NULL), has_supported_syntax_(true) { |
|
||||
} |
|
||||
|
|
||||
void Check(CompilationInfo* info); |
|
||||
|
|
||||
CompilationInfo* info() { return info_; } |
|
||||
bool has_supported_syntax() { return has_supported_syntax_; } |
|
||||
|
|
||||
private: |
|
||||
void VisitDeclarations(ZoneList<Declaration*>* decls); |
|
||||
void VisitStatements(ZoneList<Statement*>* stmts); |
|
||||
|
|
||||
// AST node visit functions.
|
|
||||
#define DECLARE_VISIT(type) virtual void Visit##type(type* node); |
|
||||
AST_NODE_LIST(DECLARE_VISIT) |
|
||||
#undef DECLARE_VISIT |
|
||||
|
|
||||
CompilationInfo* info_; |
|
||||
bool has_supported_syntax_; |
|
||||
|
|
||||
DISALLOW_COPY_AND_ASSIGN(FastCodeGenSyntaxChecker); |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
class FastCodeGenerator: public AstVisitor { |
|
||||
public: |
|
||||
explicit FastCodeGenerator(MacroAssembler* masm) |
|
||||
: masm_(masm), info_(NULL), destination_(no_reg), smi_bits_(0) { |
|
||||
} |
|
||||
|
|
||||
static Handle<Code> MakeCode(CompilationInfo* info); |
|
||||
|
|
||||
void Generate(CompilationInfo* compilation_info); |
|
||||
|
|
||||
private: |
|
||||
MacroAssembler* masm() { return masm_; } |
|
||||
CompilationInfo* info() { return info_; } |
|
||||
|
|
||||
Register destination() { return destination_; } |
|
||||
void set_destination(Register reg) { destination_ = reg; } |
|
||||
|
|
||||
FunctionLiteral* function() { return info_->function(); } |
|
||||
Scope* scope() { return info_->scope(); } |
|
||||
|
|
||||
// Platform-specific fixed registers, all guaranteed distinct.
|
|
||||
Register accumulator0(); |
|
||||
Register accumulator1(); |
|
||||
Register scratch0(); |
|
||||
Register scratch1(); |
|
||||
Register scratch2(); |
|
||||
Register receiver_reg(); |
|
||||
Register context_reg(); |
|
||||
|
|
||||
Register other_accumulator(Register reg) { |
|
||||
ASSERT(reg.is(accumulator0()) || reg.is(accumulator1())); |
|
||||
return (reg.is(accumulator0())) ? accumulator1() : accumulator0(); |
|
||||
} |
|
||||
|
|
||||
// Flags are true if the respective register is statically known to hold a
|
|
||||
// smi. We do not track every register, only the accumulator registers.
|
|
||||
bool is_smi(Register reg) { |
|
||||
ASSERT(!reg.is(no_reg)); |
|
||||
return (smi_bits_ & reg.bit()) != 0; |
|
||||
} |
|
||||
void set_as_smi(Register reg) { |
|
||||
ASSERT(!reg.is(no_reg)); |
|
||||
smi_bits_ = smi_bits_ | reg.bit(); |
|
||||
} |
|
||||
void clear_as_smi(Register reg) { |
|
||||
ASSERT(!reg.is(no_reg)); |
|
||||
smi_bits_ = smi_bits_ & ~reg.bit(); |
|
||||
} |
|
||||
|
|
||||
// AST node visit functions.
|
|
||||
#define DECLARE_VISIT(type) virtual void Visit##type(type* node); |
|
||||
AST_NODE_LIST(DECLARE_VISIT) |
|
||||
#undef DECLARE_VISIT |
|
||||
|
|
||||
// Emit code to load the receiver from the stack into receiver_reg.
|
|
||||
void EmitLoadReceiver(); |
|
||||
|
|
||||
// Emit code to load a global variable directly from a global property
|
|
||||
// cell into the destination register.
|
|
||||
void EmitGlobalVariableLoad(Handle<Object> cell); |
|
||||
|
|
||||
// Emit a store to an own property of this. The stored value is expected
|
|
||||
// in accumulator0 and the receiver in receiver_reg. The receiver
|
|
||||
// register is preserved and the result (the stored value) is left in the
|
|
||||
// destination register.
|
|
||||
void EmitThisPropertyStore(Handle<String> name); |
|
||||
|
|
||||
// Emit a load from an own property of this. The receiver is expected in
|
|
||||
// receiver_reg. The receiver register is preserved and the result is
|
|
||||
// left in the destination register.
|
|
||||
void EmitThisPropertyLoad(Handle<String> name); |
|
||||
|
|
||||
// Emit a bitwise or operation. The left operand is in accumulator1 and
|
|
||||
// the right is in accumulator0. The result should be left in the
|
|
||||
// destination register.
|
|
||||
void EmitBitOr(); |
|
||||
|
|
||||
MacroAssembler* masm_; |
|
||||
CompilationInfo* info_; |
|
||||
Register destination_; |
|
||||
uint32_t smi_bits_; |
|
||||
|
|
||||
DISALLOW_COPY_AND_ASSIGN(FastCodeGenerator); |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
} } // namespace v8::internal
|
|
||||
|
|
||||
#endif // V8_TARGET_ARCH_IA32
|
|
||||
|
|
||||
#endif // V8_FAST_CODEGEN_H_
|
|
@ -1,954 +0,0 @@ |
|||||
// Copyright 2010 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" |
|
||||
|
|
||||
#if defined(V8_TARGET_ARCH_IA32) |
|
||||
|
|
||||
#include "codegen-inl.h" |
|
||||
#include "fast-codegen.h" |
|
||||
#include "data-flow.h" |
|
||||
#include "scopes.h" |
|
||||
|
|
||||
namespace v8 { |
|
||||
namespace internal { |
|
||||
|
|
||||
#define BAILOUT(reason) \ |
|
||||
do { \ |
|
||||
if (FLAG_trace_bailout) { \ |
|
||||
PrintF("%s\n", reason); \ |
|
||||
} \ |
|
||||
has_supported_syntax_ = false; \ |
|
||||
return; \ |
|
||||
} while (false) |
|
||||
|
|
||||
|
|
||||
#define CHECK_BAILOUT \ |
|
||||
do { \ |
|
||||
if (!has_supported_syntax_) return; \ |
|
||||
} while (false) |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::Check(CompilationInfo* info) { |
|
||||
info_ = info; |
|
||||
|
|
||||
// We do not specialize if we do not have a receiver or if it is not a
|
|
||||
// JS object with fast mode properties.
|
|
||||
if (!info->has_receiver()) BAILOUT("No receiver"); |
|
||||
if (!info->receiver()->IsJSObject()) BAILOUT("Receiver is not an object"); |
|
||||
Handle<JSObject> object = Handle<JSObject>::cast(info->receiver()); |
|
||||
if (!object->HasFastProperties()) BAILOUT("Receiver is in dictionary mode"); |
|
||||
|
|
||||
// We do not support stack or heap slots (both of which require
|
|
||||
// allocation).
|
|
||||
Scope* scope = info->scope(); |
|
||||
if (scope->num_stack_slots() > 0) { |
|
||||
BAILOUT("Function has stack-allocated locals"); |
|
||||
} |
|
||||
if (scope->num_heap_slots() > 0) { |
|
||||
BAILOUT("Function has context-allocated locals"); |
|
||||
} |
|
||||
|
|
||||
VisitDeclarations(scope->declarations()); |
|
||||
CHECK_BAILOUT; |
|
||||
|
|
||||
// We do not support empty function bodies.
|
|
||||
if (info->function()->body()->is_empty()) { |
|
||||
BAILOUT("Function has an empty body"); |
|
||||
} |
|
||||
VisitStatements(info->function()->body()); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitDeclarations( |
|
||||
ZoneList<Declaration*>* decls) { |
|
||||
if (!decls->is_empty()) BAILOUT("Function has declarations"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitStatements(ZoneList<Statement*>* stmts) { |
|
||||
if (stmts->length() != 1) { |
|
||||
BAILOUT("Function body is not a singleton statement."); |
|
||||
} |
|
||||
Visit(stmts->at(0)); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitDeclaration(Declaration* decl) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitBlock(Block* stmt) { |
|
||||
VisitStatements(stmt->statements()); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitExpressionStatement( |
|
||||
ExpressionStatement* stmt) { |
|
||||
Visit(stmt->expression()); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitEmptyStatement(EmptyStatement* stmt) { |
|
||||
// Supported.
|
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitIfStatement(IfStatement* stmt) { |
|
||||
BAILOUT("IfStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitContinueStatement(ContinueStatement* stmt) { |
|
||||
BAILOUT("Continuestatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitBreakStatement(BreakStatement* stmt) { |
|
||||
BAILOUT("BreakStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitReturnStatement(ReturnStatement* stmt) { |
|
||||
BAILOUT("ReturnStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitWithEnterStatement( |
|
||||
WithEnterStatement* stmt) { |
|
||||
BAILOUT("WithEnterStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitWithExitStatement(WithExitStatement* stmt) { |
|
||||
BAILOUT("WithExitStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitSwitchStatement(SwitchStatement* stmt) { |
|
||||
BAILOUT("SwitchStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitDoWhileStatement(DoWhileStatement* stmt) { |
|
||||
BAILOUT("DoWhileStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitWhileStatement(WhileStatement* stmt) { |
|
||||
BAILOUT("WhileStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitForStatement(ForStatement* stmt) { |
|
||||
BAILOUT("ForStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitForInStatement(ForInStatement* stmt) { |
|
||||
BAILOUT("ForInStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitTryCatchStatement(TryCatchStatement* stmt) { |
|
||||
BAILOUT("TryCatchStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitTryFinallyStatement( |
|
||||
TryFinallyStatement* stmt) { |
|
||||
BAILOUT("TryFinallyStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitDebuggerStatement( |
|
||||
DebuggerStatement* stmt) { |
|
||||
BAILOUT("DebuggerStatement"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitFunctionLiteral(FunctionLiteral* expr) { |
|
||||
BAILOUT("FunctionLiteral"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitSharedFunctionInfoLiteral( |
|
||||
SharedFunctionInfoLiteral* expr) { |
|
||||
BAILOUT("SharedFunctionInfoLiteral"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitConditional(Conditional* expr) { |
|
||||
BAILOUT("Conditional"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitSlot(Slot* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitVariableProxy(VariableProxy* expr) { |
|
||||
// Only global variable references are supported.
|
|
||||
Variable* var = expr->var(); |
|
||||
if (!var->is_global() || var->is_this()) BAILOUT("Non-global variable"); |
|
||||
|
|
||||
// Check if the global variable is existing and non-deletable.
|
|
||||
if (info()->has_global_object()) { |
|
||||
LookupResult lookup; |
|
||||
info()->global_object()->Lookup(*expr->name(), &lookup); |
|
||||
if (!lookup.IsProperty()) { |
|
||||
BAILOUT("Non-existing global variable"); |
|
||||
} |
|
||||
// We do not handle global variables with accessors or interceptors.
|
|
||||
if (lookup.type() != NORMAL) { |
|
||||
BAILOUT("Global variable with accessors or interceptors."); |
|
||||
} |
|
||||
// We do not handle deletable global variables.
|
|
||||
if (!lookup.IsDontDelete()) { |
|
||||
BAILOUT("Deletable global variable"); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitLiteral(Literal* expr) { |
|
||||
BAILOUT("Literal"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitRegExpLiteral(RegExpLiteral* expr) { |
|
||||
BAILOUT("RegExpLiteral"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitObjectLiteral(ObjectLiteral* expr) { |
|
||||
BAILOUT("ObjectLiteral"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitArrayLiteral(ArrayLiteral* expr) { |
|
||||
BAILOUT("ArrayLiteral"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitCatchExtensionObject( |
|
||||
CatchExtensionObject* expr) { |
|
||||
BAILOUT("CatchExtensionObject"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitAssignment(Assignment* expr) { |
|
||||
// Simple assignments to (named) this properties are supported.
|
|
||||
if (expr->op() != Token::ASSIGN) BAILOUT("Non-simple assignment"); |
|
||||
|
|
||||
Property* prop = expr->target()->AsProperty(); |
|
||||
if (prop == NULL) BAILOUT("Non-property assignment"); |
|
||||
VariableProxy* proxy = prop->obj()->AsVariableProxy(); |
|
||||
if (proxy == NULL || !proxy->var()->is_this()) { |
|
||||
BAILOUT("Non-this-property assignment"); |
|
||||
} |
|
||||
if (!prop->key()->IsPropertyName()) { |
|
||||
BAILOUT("Non-named-property assignment"); |
|
||||
} |
|
||||
|
|
||||
// We will only specialize for fields on the object itself.
|
|
||||
// Expression::IsPropertyName implies that the name is a literal
|
|
||||
// symbol but we do not assume that.
|
|
||||
Literal* key = prop->key()->AsLiteral(); |
|
||||
if (key != NULL && key->handle()->IsString()) { |
|
||||
Handle<Object> receiver = info()->receiver(); |
|
||||
Handle<String> name = Handle<String>::cast(key->handle()); |
|
||||
LookupResult lookup; |
|
||||
receiver->Lookup(*name, &lookup); |
|
||||
if (!lookup.IsProperty()) { |
|
||||
BAILOUT("Assigned property not found at compile time"); |
|
||||
} |
|
||||
if (lookup.holder() != *receiver) BAILOUT("Non-own property assignment"); |
|
||||
if (!lookup.type() == FIELD) BAILOUT("Non-field property assignment"); |
|
||||
} else { |
|
||||
UNREACHABLE(); |
|
||||
BAILOUT("Unexpected non-string-literal property key"); |
|
||||
} |
|
||||
|
|
||||
Visit(expr->value()); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitThrow(Throw* expr) { |
|
||||
BAILOUT("Throw"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitProperty(Property* expr) { |
|
||||
// We support named this property references.
|
|
||||
VariableProxy* proxy = expr->obj()->AsVariableProxy(); |
|
||||
if (proxy == NULL || !proxy->var()->is_this()) { |
|
||||
BAILOUT("Non-this-property reference"); |
|
||||
} |
|
||||
if (!expr->key()->IsPropertyName()) { |
|
||||
BAILOUT("Non-named-property reference"); |
|
||||
} |
|
||||
|
|
||||
// We will only specialize for fields on the object itself.
|
|
||||
// Expression::IsPropertyName implies that the name is a literal
|
|
||||
// symbol but we do not assume that.
|
|
||||
Literal* key = expr->key()->AsLiteral(); |
|
||||
if (key != NULL && key->handle()->IsString()) { |
|
||||
Handle<Object> receiver = info()->receiver(); |
|
||||
Handle<String> name = Handle<String>::cast(key->handle()); |
|
||||
LookupResult lookup; |
|
||||
receiver->Lookup(*name, &lookup); |
|
||||
if (!lookup.IsProperty()) { |
|
||||
BAILOUT("Referenced property not found at compile time"); |
|
||||
} |
|
||||
if (lookup.holder() != *receiver) BAILOUT("Non-own property reference"); |
|
||||
if (!lookup.type() == FIELD) BAILOUT("Non-field property reference"); |
|
||||
} else { |
|
||||
UNREACHABLE(); |
|
||||
BAILOUT("Unexpected non-string-literal property key"); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitCall(Call* expr) { |
|
||||
BAILOUT("Call"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitCallNew(CallNew* expr) { |
|
||||
BAILOUT("CallNew"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitCallRuntime(CallRuntime* expr) { |
|
||||
BAILOUT("CallRuntime"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitUnaryOperation(UnaryOperation* expr) { |
|
||||
BAILOUT("UnaryOperation"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitCountOperation(CountOperation* expr) { |
|
||||
BAILOUT("CountOperation"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitBinaryOperation(BinaryOperation* expr) { |
|
||||
// We support bitwise OR.
|
|
||||
switch (expr->op()) { |
|
||||
case Token::COMMA: |
|
||||
BAILOUT("BinaryOperation COMMA"); |
|
||||
case Token::OR: |
|
||||
BAILOUT("BinaryOperation OR"); |
|
||||
case Token::AND: |
|
||||
BAILOUT("BinaryOperation AND"); |
|
||||
|
|
||||
case Token::BIT_OR: |
|
||||
// We support expressions nested on the left because they only require
|
|
||||
// a pair of registers to keep all intermediate values in registers
|
|
||||
// (i.e., the expression stack has height no more than two).
|
|
||||
if (!expr->right()->IsLeaf()) BAILOUT("expression nested on right"); |
|
||||
|
|
||||
// We do not allow subexpressions with side effects because we
|
|
||||
// (currently) bail out to the beginning of the full function. The
|
|
||||
// only expressions with side effects that we would otherwise handle
|
|
||||
// are assignments.
|
|
||||
if (expr->left()->AsAssignment() != NULL || |
|
||||
expr->right()->AsAssignment() != NULL) { |
|
||||
BAILOUT("subexpression of binary operation has side effects"); |
|
||||
} |
|
||||
|
|
||||
Visit(expr->left()); |
|
||||
CHECK_BAILOUT; |
|
||||
Visit(expr->right()); |
|
||||
break; |
|
||||
|
|
||||
case Token::BIT_XOR: |
|
||||
BAILOUT("BinaryOperation BIT_XOR"); |
|
||||
case Token::BIT_AND: |
|
||||
BAILOUT("BinaryOperation BIT_AND"); |
|
||||
case Token::SHL: |
|
||||
BAILOUT("BinaryOperation SHL"); |
|
||||
case Token::SAR: |
|
||||
BAILOUT("BinaryOperation SAR"); |
|
||||
case Token::SHR: |
|
||||
BAILOUT("BinaryOperation SHR"); |
|
||||
case Token::ADD: |
|
||||
BAILOUT("BinaryOperation ADD"); |
|
||||
case Token::SUB: |
|
||||
BAILOUT("BinaryOperation SUB"); |
|
||||
case Token::MUL: |
|
||||
BAILOUT("BinaryOperation MUL"); |
|
||||
case Token::DIV: |
|
||||
BAILOUT("BinaryOperation DIV"); |
|
||||
case Token::MOD: |
|
||||
BAILOUT("BinaryOperation MOD"); |
|
||||
default: |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitCompareOperation(CompareOperation* expr) { |
|
||||
BAILOUT("CompareOperation"); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenSyntaxChecker::VisitThisFunction(ThisFunction* expr) { |
|
||||
BAILOUT("ThisFunction"); |
|
||||
} |
|
||||
|
|
||||
#undef BAILOUT |
|
||||
#undef CHECK_BAILOUT |
|
||||
|
|
||||
|
|
||||
#define __ ACCESS_MASM(masm()) |
|
||||
|
|
||||
Handle<Code> FastCodeGenerator::MakeCode(CompilationInfo* info) { |
|
||||
// Label the AST before calling MakeCodePrologue, so AST node numbers are
|
|
||||
// printed with the AST.
|
|
||||
AstLabeler labeler; |
|
||||
labeler.Label(info); |
|
||||
|
|
||||
CodeGenerator::MakeCodePrologue(info); |
|
||||
|
|
||||
const int kInitialBufferSize = 4 * KB; |
|
||||
MacroAssembler masm(NULL, kInitialBufferSize); |
|
||||
|
|
||||
// Generate the fast-path code.
|
|
||||
FastCodeGenerator fast_cgen(&masm); |
|
||||
fast_cgen.Generate(info); |
|
||||
if (fast_cgen.HasStackOverflow()) { |
|
||||
ASSERT(!Top::has_pending_exception()); |
|
||||
return Handle<Code>::null(); |
|
||||
} |
|
||||
|
|
||||
// Generate the full code for the function in bailout mode, using the same
|
|
||||
// macro assembler.
|
|
||||
CodeGenerator cgen(&masm); |
|
||||
CodeGeneratorScope scope(&cgen); |
|
||||
info->set_mode(CompilationInfo::SECONDARY); |
|
||||
cgen.Generate(info); |
|
||||
if (cgen.HasStackOverflow()) { |
|
||||
ASSERT(!Top::has_pending_exception()); |
|
||||
return Handle<Code>::null(); |
|
||||
} |
|
||||
|
|
||||
Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, NOT_IN_LOOP); |
|
||||
return CodeGenerator::MakeCodeEpilogue(&masm, flags, info); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
Register FastCodeGenerator::accumulator0() { return eax; } |
|
||||
Register FastCodeGenerator::accumulator1() { return edx; } |
|
||||
Register FastCodeGenerator::scratch0() { return ecx; } |
|
||||
Register FastCodeGenerator::scratch1() { return edi; } |
|
||||
Register FastCodeGenerator::receiver_reg() { return ebx; } |
|
||||
Register FastCodeGenerator::context_reg() { return esi; } |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::EmitLoadReceiver() { |
|
||||
// Offset 2 is due to return address and saved frame pointer.
|
|
||||
int index = 2 + function()->scope()->num_parameters(); |
|
||||
__ mov(receiver_reg(), Operand(ebp, index * kPointerSize)); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::EmitGlobalVariableLoad(Handle<Object> cell) { |
|
||||
ASSERT(!destination().is(no_reg)); |
|
||||
ASSERT(cell->IsJSGlobalPropertyCell()); |
|
||||
|
|
||||
__ mov(destination(), Immediate(cell)); |
|
||||
__ mov(destination(), |
|
||||
FieldOperand(destination(), JSGlobalPropertyCell::kValueOffset)); |
|
||||
if (FLAG_debug_code) { |
|
||||
__ cmp(destination(), Factory::the_hole_value()); |
|
||||
__ Check(not_equal, "DontDelete cells can't contain the hole"); |
|
||||
} |
|
||||
|
|
||||
// The loaded value is not known to be a smi.
|
|
||||
clear_as_smi(destination()); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::EmitThisPropertyStore(Handle<String> name) { |
|
||||
LookupResult lookup; |
|
||||
info()->receiver()->Lookup(*name, &lookup); |
|
||||
|
|
||||
ASSERT(lookup.holder() == *info()->receiver()); |
|
||||
ASSERT(lookup.type() == FIELD); |
|
||||
Handle<Map> map(Handle<HeapObject>::cast(info()->receiver())->map()); |
|
||||
int index = lookup.GetFieldIndex() - map->inobject_properties(); |
|
||||
int offset = index * kPointerSize; |
|
||||
|
|
||||
// We will emit the write barrier unless the stored value is statically
|
|
||||
// known to be a smi.
|
|
||||
bool needs_write_barrier = !is_smi(accumulator0()); |
|
||||
|
|
||||
// Perform the store. Negative offsets are inobject properties.
|
|
||||
if (offset < 0) { |
|
||||
offset += map->instance_size(); |
|
||||
__ mov(FieldOperand(receiver_reg(), offset), accumulator0()); |
|
||||
if (needs_write_barrier) { |
|
||||
// Preserve receiver from write barrier.
|
|
||||
__ mov(scratch0(), receiver_reg()); |
|
||||
} |
|
||||
} else { |
|
||||
offset += FixedArray::kHeaderSize; |
|
||||
__ mov(scratch0(), |
|
||||
FieldOperand(receiver_reg(), JSObject::kPropertiesOffset)); |
|
||||
__ mov(FieldOperand(scratch0(), offset), accumulator0()); |
|
||||
} |
|
||||
|
|
||||
if (needs_write_barrier) { |
|
||||
if (destination().is(no_reg)) { |
|
||||
// After RecordWrite accumulator0 is only accidently a smi, but it is
|
|
||||
// already marked as not known to be one.
|
|
||||
__ RecordWrite(scratch0(), offset, accumulator0(), scratch1()); |
|
||||
} else { |
|
||||
// Copy the value to the other accumulator to preserve a copy from the
|
|
||||
// write barrier. One of the accumulators is available as a scratch
|
|
||||
// register. Neither is a smi.
|
|
||||
__ mov(accumulator1(), accumulator0()); |
|
||||
clear_as_smi(accumulator1()); |
|
||||
Register value_scratch = other_accumulator(destination()); |
|
||||
__ RecordWrite(scratch0(), offset, value_scratch, scratch1()); |
|
||||
} |
|
||||
} else if (destination().is(accumulator1())) { |
|
||||
__ mov(accumulator1(), accumulator0()); |
|
||||
// Is a smi because we do not need the write barrier.
|
|
||||
set_as_smi(accumulator1()); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::EmitThisPropertyLoad(Handle<String> name) { |
|
||||
ASSERT(!destination().is(no_reg)); |
|
||||
LookupResult lookup; |
|
||||
info()->receiver()->Lookup(*name, &lookup); |
|
||||
|
|
||||
ASSERT(lookup.holder() == *info()->receiver()); |
|
||||
ASSERT(lookup.type() == FIELD); |
|
||||
Handle<Map> map(Handle<HeapObject>::cast(info()->receiver())->map()); |
|
||||
int index = lookup.GetFieldIndex() - map->inobject_properties(); |
|
||||
int offset = index * kPointerSize; |
|
||||
|
|
||||
// Perform the load. Negative offsets are inobject properties.
|
|
||||
if (offset < 0) { |
|
||||
offset += map->instance_size(); |
|
||||
__ mov(destination(), FieldOperand(receiver_reg(), offset)); |
|
||||
} else { |
|
||||
offset += FixedArray::kHeaderSize; |
|
||||
__ mov(scratch0(), |
|
||||
FieldOperand(receiver_reg(), JSObject::kPropertiesOffset)); |
|
||||
__ mov(destination(), FieldOperand(scratch0(), offset)); |
|
||||
} |
|
||||
|
|
||||
// The loaded value is not known to be a smi.
|
|
||||
clear_as_smi(destination()); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::EmitBitOr() { |
|
||||
if (is_smi(accumulator0()) && is_smi(accumulator1())) { |
|
||||
// If both operands are known to be a smi then there is no need to check
|
|
||||
// the operands or result. There is no need to perform the operation in
|
|
||||
// an effect context.
|
|
||||
if (!destination().is(no_reg)) { |
|
||||
// Leave the result in the destination register. Bitwise or is
|
|
||||
// commutative.
|
|
||||
__ or_(destination(), Operand(other_accumulator(destination()))); |
|
||||
} |
|
||||
} else { |
|
||||
// Left is in accumulator1, right in accumulator0.
|
|
||||
Label* bailout = NULL; |
|
||||
if (destination().is(accumulator0())) { |
|
||||
__ mov(scratch0(), accumulator0()); |
|
||||
__ or_(destination(), Operand(accumulator1())); // Or is commutative.
|
|
||||
__ test(destination(), Immediate(kSmiTagMask)); |
|
||||
bailout = info()->AddBailout(accumulator1(), scratch0()); // Left, right.
|
|
||||
} else if (destination().is(accumulator1())) { |
|
||||
__ mov(scratch0(), accumulator1()); |
|
||||
__ or_(destination(), Operand(accumulator0())); |
|
||||
__ test(destination(), Immediate(kSmiTagMask)); |
|
||||
bailout = info()->AddBailout(scratch0(), accumulator0()); |
|
||||
} else { |
|
||||
ASSERT(destination().is(no_reg)); |
|
||||
__ mov(scratch0(), accumulator1()); |
|
||||
__ or_(scratch0(), Operand(accumulator0())); |
|
||||
__ test(scratch0(), Immediate(kSmiTagMask)); |
|
||||
bailout = info()->AddBailout(accumulator1(), accumulator0()); |
|
||||
} |
|
||||
__ j(not_zero, bailout, not_taken); |
|
||||
} |
|
||||
|
|
||||
// If we didn't bailout, the result (in fact, both inputs too) is known to
|
|
||||
// be a smi.
|
|
||||
set_as_smi(accumulator0()); |
|
||||
set_as_smi(accumulator1()); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::Generate(CompilationInfo* compilation_info) { |
|
||||
ASSERT(info_ == NULL); |
|
||||
info_ = compilation_info; |
|
||||
Comment cmnt(masm_, "[ function compiled by fast code generator"); |
|
||||
|
|
||||
// Save the caller's frame pointer and set up our own.
|
|
||||
Comment prologue_cmnt(masm(), ";; Prologue"); |
|
||||
__ push(ebp); |
|
||||
__ mov(ebp, esp); |
|
||||
__ push(esi); // Context.
|
|
||||
__ push(edi); // Closure.
|
|
||||
// Note that we keep a live register reference to esi (context) at this
|
|
||||
// point.
|
|
||||
|
|
||||
Label* bailout_to_beginning = info()->AddBailout(); |
|
||||
// Receiver (this) is allocated to a fixed register.
|
|
||||
if (info()->has_this_properties()) { |
|
||||
Comment cmnt(masm(), ";; MapCheck(this)"); |
|
||||
if (FLAG_print_ir) { |
|
||||
PrintF("#: MapCheck(this)\n"); |
|
||||
} |
|
||||
ASSERT(info()->has_receiver() && info()->receiver()->IsHeapObject()); |
|
||||
Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver()); |
|
||||
Handle<Map> map(object->map()); |
|
||||
EmitLoadReceiver(); |
|
||||
__ CheckMap(receiver_reg(), map, bailout_to_beginning, false); |
|
||||
} |
|
||||
|
|
||||
// If there is a global variable access check if the global object is the
|
|
||||
// same as at lazy-compilation time.
|
|
||||
if (info()->has_globals()) { |
|
||||
Comment cmnt(masm(), ";; MapCheck(GLOBAL)"); |
|
||||
if (FLAG_print_ir) { |
|
||||
PrintF("#: MapCheck(GLOBAL)\n"); |
|
||||
} |
|
||||
ASSERT(info()->has_global_object()); |
|
||||
Handle<Map> map(info()->global_object()->map()); |
|
||||
__ mov(scratch0(), CodeGenerator::GlobalObject()); |
|
||||
__ CheckMap(scratch0(), map, bailout_to_beginning, true); |
|
||||
} |
|
||||
|
|
||||
VisitStatements(function()->body()); |
|
||||
|
|
||||
Comment return_cmnt(masm(), ";; Return(<undefined>)"); |
|
||||
if (FLAG_print_ir) { |
|
||||
PrintF("#: Return(<undefined>)\n"); |
|
||||
} |
|
||||
__ mov(eax, Factory::undefined_value()); |
|
||||
__ mov(esp, ebp); |
|
||||
__ pop(ebp); |
|
||||
__ ret((scope()->num_parameters() + 1) * kPointerSize); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitDeclaration(Declaration* decl) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitBlock(Block* stmt) { |
|
||||
VisitStatements(stmt->statements()); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { |
|
||||
Visit(stmt->expression()); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) { |
|
||||
// Nothing to do.
|
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitIfStatement(IfStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitBreakStatement(BreakStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitWithEnterStatement(WithEnterStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitWithExitStatement(WithExitStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitWhileStatement(WhileStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitForStatement(ForStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitSharedFunctionInfoLiteral( |
|
||||
SharedFunctionInfoLiteral* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitConditional(Conditional* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitSlot(Slot* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { |
|
||||
ASSERT(expr->var()->is_global() && !expr->var()->is_this()); |
|
||||
// Check if we can compile a global variable load directly from the cell.
|
|
||||
ASSERT(info()->has_global_object()); |
|
||||
LookupResult lookup; |
|
||||
info()->global_object()->Lookup(*expr->name(), &lookup); |
|
||||
// We only support normal (non-accessor/interceptor) DontDelete properties
|
|
||||
// for now.
|
|
||||
ASSERT(lookup.IsProperty()); |
|
||||
ASSERT_EQ(NORMAL, lookup.type()); |
|
||||
ASSERT(lookup.IsDontDelete()); |
|
||||
Handle<Object> cell(info()->global_object()->GetPropertyCell(&lookup)); |
|
||||
|
|
||||
// Global variable lookups do not have side effects, so we do not need to
|
|
||||
// emit code if we are in an effect context.
|
|
||||
if (!destination().is(no_reg)) { |
|
||||
Comment cmnt(masm(), ";; Global"); |
|
||||
if (FLAG_print_ir) { |
|
||||
SmartPointer<char> name = expr->name()->ToCString(); |
|
||||
PrintF("%d: t%d = Global(%s)\n", expr->num(), |
|
||||
expr->num(), *name); |
|
||||
} |
|
||||
EmitGlobalVariableLoad(cell); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitLiteral(Literal* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitAssignment(Assignment* expr) { |
|
||||
// Known to be a simple this property assignment. Effectively a unary
|
|
||||
// operation.
|
|
||||
{ Register my_destination = destination(); |
|
||||
set_destination(accumulator0()); |
|
||||
Visit(expr->value()); |
|
||||
set_destination(my_destination); |
|
||||
} |
|
||||
|
|
||||
Property* prop = expr->target()->AsProperty(); |
|
||||
ASSERT_NOT_NULL(prop); |
|
||||
ASSERT_NOT_NULL(prop->obj()->AsVariableProxy()); |
|
||||
ASSERT(prop->obj()->AsVariableProxy()->var()->is_this()); |
|
||||
ASSERT(prop->key()->IsPropertyName()); |
|
||||
Handle<String> name = |
|
||||
Handle<String>::cast(prop->key()->AsLiteral()->handle()); |
|
||||
|
|
||||
Comment cmnt(masm(), ";; Store to this"); |
|
||||
if (FLAG_print_ir) { |
|
||||
SmartPointer<char> name_string = name->ToCString(); |
|
||||
PrintF("%d: ", expr->num()); |
|
||||
if (!destination().is(no_reg)) PrintF("t%d = ", expr->num()); |
|
||||
PrintF("Store(this, \"%s\", t%d)\n", *name_string, |
|
||||
expr->value()->num()); |
|
||||
} |
|
||||
|
|
||||
EmitThisPropertyStore(name); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitThrow(Throw* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitProperty(Property* expr) { |
|
||||
ASSERT_NOT_NULL(expr->obj()->AsVariableProxy()); |
|
||||
ASSERT(expr->obj()->AsVariableProxy()->var()->is_this()); |
|
||||
ASSERT(expr->key()->IsPropertyName()); |
|
||||
if (!destination().is(no_reg)) { |
|
||||
Handle<String> name = |
|
||||
Handle<String>::cast(expr->key()->AsLiteral()->handle()); |
|
||||
|
|
||||
Comment cmnt(masm(), ";; Load from this"); |
|
||||
if (FLAG_print_ir) { |
|
||||
SmartPointer<char> name_string = name->ToCString(); |
|
||||
PrintF("%d: t%d = Load(this, \"%s\")\n", |
|
||||
expr->num(), expr->num(), *name_string); |
|
||||
} |
|
||||
EmitThisPropertyLoad(name); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitCall(Call* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitCallNew(CallNew* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitCountOperation(CountOperation* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { |
|
||||
// We support limited binary operations: bitwise OR only allowed to be
|
|
||||
// nested on the left.
|
|
||||
ASSERT(expr->op() == Token::BIT_OR); |
|
||||
ASSERT(expr->right()->IsLeaf()); |
|
||||
|
|
||||
{ Register my_destination = destination(); |
|
||||
set_destination(accumulator1()); |
|
||||
Visit(expr->left()); |
|
||||
set_destination(accumulator0()); |
|
||||
Visit(expr->right()); |
|
||||
set_destination(my_destination); |
|
||||
} |
|
||||
|
|
||||
Comment cmnt(masm(), ";; BIT_OR"); |
|
||||
if (FLAG_print_ir) { |
|
||||
PrintF("%d: ", expr->num()); |
|
||||
if (!destination().is(no_reg)) PrintF("t%d = ", expr->num()); |
|
||||
PrintF("BIT_OR(t%d, t%d)\n", expr->left()->num(), expr->right()->num()); |
|
||||
} |
|
||||
EmitBitOr(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) { |
|
||||
UNREACHABLE(); |
|
||||
} |
|
||||
|
|
||||
#undef __ |
|
||||
|
|
||||
|
|
||||
} } // namespace v8::internal
|
|
||||
|
|
||||
#endif // V8_TARGET_ARCH_IA32
|
|
@ -1,155 +0,0 @@ |
|||||
// Copyright 2010 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_FAST_CODEGEN_IA32_H_ |
|
||||
#define V8_FAST_CODEGEN_IA32_H_ |
|
||||
|
|
||||
#include "v8.h" |
|
||||
|
|
||||
#include "ast.h" |
|
||||
#include "compiler.h" |
|
||||
#include "list.h" |
|
||||
|
|
||||
namespace v8 { |
|
||||
namespace internal { |
|
||||
|
|
||||
class FastCodeGenSyntaxChecker: public AstVisitor { |
|
||||
public: |
|
||||
explicit FastCodeGenSyntaxChecker() |
|
||||
: info_(NULL), has_supported_syntax_(true) { |
|
||||
} |
|
||||
|
|
||||
void Check(CompilationInfo* info); |
|
||||
|
|
||||
CompilationInfo* info() { return info_; } |
|
||||
bool has_supported_syntax() { return has_supported_syntax_; } |
|
||||
|
|
||||
private: |
|
||||
void VisitDeclarations(ZoneList<Declaration*>* decls); |
|
||||
void VisitStatements(ZoneList<Statement*>* stmts); |
|
||||
|
|
||||
// AST node visit functions.
|
|
||||
#define DECLARE_VISIT(type) virtual void Visit##type(type* node); |
|
||||
AST_NODE_LIST(DECLARE_VISIT) |
|
||||
#undef DECLARE_VISIT |
|
||||
|
|
||||
CompilationInfo* info_; |
|
||||
bool has_supported_syntax_; |
|
||||
|
|
||||
DISALLOW_COPY_AND_ASSIGN(FastCodeGenSyntaxChecker); |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
class FastCodeGenerator: public AstVisitor { |
|
||||
public: |
|
||||
explicit FastCodeGenerator(MacroAssembler* masm) |
|
||||
: masm_(masm), info_(NULL), destination_(no_reg), smi_bits_(0) { |
|
||||
} |
|
||||
|
|
||||
static Handle<Code> MakeCode(CompilationInfo* info); |
|
||||
|
|
||||
void Generate(CompilationInfo* compilation_info); |
|
||||
|
|
||||
private: |
|
||||
MacroAssembler* masm() { return masm_; } |
|
||||
CompilationInfo* info() { return info_; } |
|
||||
|
|
||||
Register destination() { return destination_; } |
|
||||
void set_destination(Register reg) { destination_ = reg; } |
|
||||
|
|
||||
FunctionLiteral* function() { return info_->function(); } |
|
||||
Scope* scope() { return info_->scope(); } |
|
||||
|
|
||||
// Platform-specific fixed registers, all guaranteed distinct.
|
|
||||
Register accumulator0(); |
|
||||
Register accumulator1(); |
|
||||
Register scratch0(); |
|
||||
Register scratch1(); |
|
||||
Register receiver_reg(); |
|
||||
Register context_reg(); |
|
||||
|
|
||||
Register other_accumulator(Register reg) { |
|
||||
ASSERT(reg.is(accumulator0()) || reg.is(accumulator1())); |
|
||||
return (reg.is(accumulator0())) ? accumulator1() : accumulator0(); |
|
||||
} |
|
||||
|
|
||||
// Flags are true if the respective register is statically known to hold a
|
|
||||
// smi. We do not track every register, only the accumulator registers.
|
|
||||
bool is_smi(Register reg) { |
|
||||
ASSERT(!reg.is(no_reg)); |
|
||||
return (smi_bits_ & reg.bit()) != 0; |
|
||||
} |
|
||||
void set_as_smi(Register reg) { |
|
||||
ASSERT(!reg.is(no_reg)); |
|
||||
smi_bits_ = smi_bits_ | reg.bit(); |
|
||||
} |
|
||||
void clear_as_smi(Register reg) { |
|
||||
ASSERT(!reg.is(no_reg)); |
|
||||
smi_bits_ = smi_bits_ & ~reg.bit(); |
|
||||
} |
|
||||
|
|
||||
// AST node visit functions.
|
|
||||
#define DECLARE_VISIT(type) virtual void Visit##type(type* node); |
|
||||
AST_NODE_LIST(DECLARE_VISIT) |
|
||||
#undef DECLARE_VISIT |
|
||||
|
|
||||
// Emit code to load the receiver from the stack into receiver_reg.
|
|
||||
void EmitLoadReceiver(); |
|
||||
|
|
||||
// Emit code to load a global variable directly from a global property
|
|
||||
// cell into the destination register.
|
|
||||
void EmitGlobalVariableLoad(Handle<Object> cell); |
|
||||
|
|
||||
// Emit a store to an own property of this. The stored value is expected
|
|
||||
// in accumulator0 and the receiver in receiver_reg. The receiver
|
|
||||
// register is preserved and the result (the stored value) is left in the
|
|
||||
// destination register.
|
|
||||
void EmitThisPropertyStore(Handle<String> name); |
|
||||
|
|
||||
// Emit a load from an own property of this. The receiver is expected in
|
|
||||
// receiver_reg. The receiver register is preserved and the result is
|
|
||||
// left in the destination register.
|
|
||||
void EmitThisPropertyLoad(Handle<String> name); |
|
||||
|
|
||||
// Emit a bitwise or operation. The left operand is in accumulator1 and
|
|
||||
// the right is in accumulator0. The result should be left in the
|
|
||||
// destination register.
|
|
||||
void EmitBitOr(); |
|
||||
|
|
||||
MacroAssembler* masm_; |
|
||||
CompilationInfo* info_; |
|
||||
|
|
||||
Register destination_; |
|
||||
uint32_t smi_bits_; |
|
||||
|
|
||||
DISALLOW_COPY_AND_ASSIGN(FastCodeGenerator); |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
} } // namespace v8::internal
|
|
||||
|
|
||||
#endif // V8_FAST_CODEGEN_IA32_H_
|
|
@ -0,0 +1,139 @@ |
|||||
|
// Copyright 2009 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 "ic-inl.h" |
||||
|
#include "objects-visiting.h" |
||||
|
|
||||
|
namespace v8 { |
||||
|
namespace internal { |
||||
|
|
||||
|
|
||||
|
static inline bool IsShortcutCandidate(int type) { |
||||
|
return ((type & kShortcutTypeMask) == kShortcutTypeTag); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId( |
||||
|
int instance_type, |
||||
|
int instance_size) { |
||||
|
if (instance_type < FIRST_NONSTRING_TYPE) { |
||||
|
switch (instance_type & kStringRepresentationMask) { |
||||
|
case kSeqStringTag: |
||||
|
if ((instance_type & kStringEncodingMask) == kAsciiStringTag) { |
||||
|
return kVisitSeqAsciiString; |
||||
|
} else { |
||||
|
return kVisitSeqTwoByteString; |
||||
|
} |
||||
|
|
||||
|
case kConsStringTag: |
||||
|
if (IsShortcutCandidate(instance_type)) { |
||||
|
return kVisitShortcutCandidate; |
||||
|
} else { |
||||
|
return kVisitConsString; |
||||
|
} |
||||
|
|
||||
|
case kExternalStringTag: |
||||
|
return GetVisitorIdForSize(kVisitDataObject, |
||||
|
kVisitDataObjectGeneric, |
||||
|
ExternalString::kSize); |
||||
|
} |
||||
|
UNREACHABLE(); |
||||
|
} |
||||
|
|
||||
|
switch (instance_type) { |
||||
|
case BYTE_ARRAY_TYPE: |
||||
|
return kVisitByteArray; |
||||
|
|
||||
|
case FIXED_ARRAY_TYPE: |
||||
|
return kVisitFixedArray; |
||||
|
|
||||
|
case ODDBALL_TYPE: |
||||
|
return kVisitOddball; |
||||
|
|
||||
|
case MAP_TYPE: |
||||
|
return kVisitMap; |
||||
|
|
||||
|
case CODE_TYPE: |
||||
|
return kVisitCode; |
||||
|
|
||||
|
case JS_GLOBAL_PROPERTY_CELL_TYPE: |
||||
|
return kVisitPropertyCell; |
||||
|
|
||||
|
case SHARED_FUNCTION_INFO_TYPE: |
||||
|
return kVisitSharedFunctionInfo; |
||||
|
|
||||
|
case PROXY_TYPE: |
||||
|
return GetVisitorIdForSize(kVisitDataObject, |
||||
|
kVisitDataObjectGeneric, |
||||
|
Proxy::kSize); |
||||
|
|
||||
|
case FILLER_TYPE: |
||||
|
return kVisitDataObjectGeneric; |
||||
|
|
||||
|
case JS_OBJECT_TYPE: |
||||
|
case JS_CONTEXT_EXTENSION_OBJECT_TYPE: |
||||
|
case JS_VALUE_TYPE: |
||||
|
case JS_ARRAY_TYPE: |
||||
|
case JS_REGEXP_TYPE: |
||||
|
case JS_FUNCTION_TYPE: |
||||
|
case JS_GLOBAL_PROXY_TYPE: |
||||
|
case JS_GLOBAL_OBJECT_TYPE: |
||||
|
case JS_BUILTINS_OBJECT_TYPE: |
||||
|
return GetVisitorIdForSize(kVisitJSObject, |
||||
|
kVisitJSObjectGeneric, |
||||
|
instance_size); |
||||
|
|
||||
|
case HEAP_NUMBER_TYPE: |
||||
|
case PIXEL_ARRAY_TYPE: |
||||
|
case EXTERNAL_BYTE_ARRAY_TYPE: |
||||
|
case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE: |
||||
|
case EXTERNAL_SHORT_ARRAY_TYPE: |
||||
|
case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE: |
||||
|
case EXTERNAL_INT_ARRAY_TYPE: |
||||
|
case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE: |
||||
|
case EXTERNAL_FLOAT_ARRAY_TYPE: |
||||
|
return GetVisitorIdForSize(kVisitDataObject, |
||||
|
kVisitDataObjectGeneric, |
||||
|
instance_size); |
||||
|
|
||||
|
#define MAKE_STRUCT_CASE(NAME, Name, name) \ |
||||
|
case NAME##_TYPE: |
||||
|
STRUCT_LIST(MAKE_STRUCT_CASE) |
||||
|
#undef MAKE_STRUCT_CASE |
||||
|
return GetVisitorIdForSize(kVisitStruct, |
||||
|
kVisitStructGeneric, |
||||
|
instance_size); |
||||
|
|
||||
|
default: |
||||
|
UNREACHABLE(); |
||||
|
return kVisitorIdCount; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} } // namespace v8::internal
|
@ -0,0 +1,382 @@ |
|||||
|
// Copyright 2006-2009 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_OBJECTS_ITERATION_H_ |
||||
|
#define V8_OBJECTS_ITERATION_H_ |
||||
|
|
||||
|
// This file provides base classes and auxiliary methods for defining
|
||||
|
// static object visitors used during GC.
|
||||
|
// Visiting HeapObject body with a normal ObjectVisitor requires performing
|
||||
|
// two switches on object's instance type to determine object size and layout
|
||||
|
// and one or more virtual method calls on visitor itself.
|
||||
|
// Static visitor is different: it provides a dispatch table which contains
|
||||
|
// pointers to specialized visit functions. Each map has the visitor_id
|
||||
|
// field which contains an index of specialized visitor to use.
|
||||
|
|
||||
|
namespace v8 { |
||||
|
namespace internal { |
||||
|
|
||||
|
|
||||
|
// Base class for all static visitors.
|
||||
|
class StaticVisitorBase : public AllStatic { |
||||
|
public: |
||||
|
enum VisitorId { |
||||
|
kVisitSeqAsciiString = 0, |
||||
|
kVisitSeqTwoByteString, |
||||
|
kVisitShortcutCandidate, |
||||
|
kVisitByteArray, |
||||
|
kVisitFixedArray, |
||||
|
|
||||
|
// For data objects, JS objects and structs along with generic visitor which
|
||||
|
// can visit object of any size we provide visitors specialized by
|
||||
|
// object size in words.
|
||||
|
// Ids of specialized visitors are declared in a linear order (without
|
||||
|
// holes) starting from the id of visitor specialized for 2 words objects
|
||||
|
// (base visitor id) and ending with the id of generic visitor.
|
||||
|
// Method GetVisitorIdForSize depends on this ordering to calculate visitor
|
||||
|
// id of specialized visitor from given instance size, base visitor id and
|
||||
|
// generic visitor's id.
|
||||
|
|
||||
|
kVisitDataObject, |
||||
|
kVisitDataObject2 = kVisitDataObject, |
||||
|
kVisitDataObject3, |
||||
|
kVisitDataObject4, |
||||
|
kVisitDataObject5, |
||||
|
kVisitDataObject6, |
||||
|
kVisitDataObject7, |
||||
|
kVisitDataObject8, |
||||
|
kVisitDataObject9, |
||||
|
kVisitDataObjectGeneric, |
||||
|
|
||||
|
kVisitJSObject, |
||||
|
kVisitJSObject2 = kVisitJSObject, |
||||
|
kVisitJSObject3, |
||||
|
kVisitJSObject4, |
||||
|
kVisitJSObject5, |
||||
|
kVisitJSObject6, |
||||
|
kVisitJSObject7, |
||||
|
kVisitJSObject8, |
||||
|
kVisitJSObject9, |
||||
|
kVisitJSObjectGeneric, |
||||
|
|
||||
|
kVisitStruct, |
||||
|
kVisitStruct2 = kVisitStruct, |
||||
|
kVisitStruct3, |
||||
|
kVisitStruct4, |
||||
|
kVisitStruct5, |
||||
|
kVisitStruct6, |
||||
|
kVisitStruct7, |
||||
|
kVisitStruct8, |
||||
|
kVisitStruct9, |
||||
|
kVisitStructGeneric, |
||||
|
|
||||
|
kVisitConsString, |
||||
|
kVisitOddball, |
||||
|
kVisitCode, |
||||
|
kVisitMap, |
||||
|
kVisitPropertyCell, |
||||
|
kVisitSharedFunctionInfo, |
||||
|
|
||||
|
kVisitorIdCount, |
||||
|
kMinObjectSizeInWords = 2 |
||||
|
}; |
||||
|
|
||||
|
// Determine which specialized visitor should be used for given instance type
|
||||
|
// and instance type.
|
||||
|
static VisitorId GetVisitorId(int instance_type, int instance_size); |
||||
|
|
||||
|
static VisitorId GetVisitorId(Map* map) { |
||||
|
return GetVisitorId(map->instance_type(), map->instance_size()); |
||||
|
} |
||||
|
|
||||
|
// For visitors that allow specialization by size calculate VisitorId based
|
||||
|
// on size, base visitor id and generic visitor id.
|
||||
|
static VisitorId GetVisitorIdForSize(VisitorId base, |
||||
|
VisitorId generic, |
||||
|
int object_size) { |
||||
|
ASSERT((base == kVisitDataObject) || |
||||
|
(base == kVisitStruct) || |
||||
|
(base == kVisitJSObject)); |
||||
|
ASSERT(IsAligned(object_size, kPointerSize)); |
||||
|
ASSERT(kMinObjectSizeInWords * kPointerSize <= object_size); |
||||
|
ASSERT(object_size < Page::kMaxHeapObjectSize); |
||||
|
|
||||
|
const VisitorId specialization = static_cast<VisitorId>( |
||||
|
base + (object_size >> kPointerSizeLog2) - kMinObjectSizeInWords); |
||||
|
|
||||
|
return Min(specialization, generic); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
template<typename Callback> |
||||
|
class VisitorDispatchTable { |
||||
|
public: |
||||
|
inline Callback GetVisitor(Map* map) { |
||||
|
return callbacks_[map->visitor_id()]; |
||||
|
} |
||||
|
|
||||
|
void Register(StaticVisitorBase::VisitorId id, Callback callback) { |
||||
|
ASSERT((0 <= id) && (id < StaticVisitorBase::kVisitorIdCount)); |
||||
|
callbacks_[id] = callback; |
||||
|
} |
||||
|
|
||||
|
template<typename Visitor, |
||||
|
StaticVisitorBase::VisitorId base, |
||||
|
StaticVisitorBase::VisitorId generic, |
||||
|
int object_size_in_words> |
||||
|
void RegisterSpecialization() { |
||||
|
static const int size = object_size_in_words * kPointerSize; |
||||
|
Register(StaticVisitorBase::GetVisitorIdForSize(base, generic, size), |
||||
|
&Visitor::template VisitSpecialized<size>); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
template<typename Visitor, |
||||
|
StaticVisitorBase::VisitorId base, |
||||
|
StaticVisitorBase::VisitorId generic> |
||||
|
void RegisterSpecializations() { |
||||
|
STATIC_ASSERT( |
||||
|
(generic - base + StaticVisitorBase::kMinObjectSizeInWords) == 10); |
||||
|
RegisterSpecialization<Visitor, base, generic, 2>(); |
||||
|
RegisterSpecialization<Visitor, base, generic, 3>(); |
||||
|
RegisterSpecialization<Visitor, base, generic, 4>(); |
||||
|
RegisterSpecialization<Visitor, base, generic, 5>(); |
||||
|
RegisterSpecialization<Visitor, base, generic, 6>(); |
||||
|
RegisterSpecialization<Visitor, base, generic, 7>(); |
||||
|
RegisterSpecialization<Visitor, base, generic, 8>(); |
||||
|
RegisterSpecialization<Visitor, base, generic, 9>(); |
||||
|
Register(generic, &Visitor::Visit); |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
Callback callbacks_[StaticVisitorBase::kVisitorIdCount]; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
template<typename StaticVisitor> |
||||
|
class BodyVisitorBase : public AllStatic { |
||||
|
public: |
||||
|
static inline void IteratePointers(HeapObject* object, |
||||
|
int start_offset, |
||||
|
int end_offset) { |
||||
|
Object** start_slot = reinterpret_cast<Object**>(object->address() + |
||||
|
start_offset); |
||||
|
Object** end_slot = reinterpret_cast<Object**>(object->address() + |
||||
|
end_offset); |
||||
|
StaticVisitor::VisitPointers(start_slot, end_slot); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
template<typename StaticVisitor, typename BodyDescriptor, typename ReturnType> |
||||
|
class FlexibleBodyVisitor : public BodyVisitorBase<StaticVisitor> { |
||||
|
public: |
||||
|
static inline ReturnType Visit(Map* map, HeapObject* object) { |
||||
|
int object_size = BodyDescriptor::SizeOf(map, object); |
||||
|
IteratePointers(object, BodyDescriptor::kStartOffset, object_size); |
||||
|
return static_cast<ReturnType>(object_size); |
||||
|
} |
||||
|
|
||||
|
template<int object_size> |
||||
|
static inline ReturnType VisitSpecialized(Map* map, HeapObject* object) { |
||||
|
IteratePointers(object, BodyDescriptor::kStartOffset, object_size); |
||||
|
return static_cast<ReturnType>(object_size); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
template<typename StaticVisitor, typename BodyDescriptor, typename ReturnType> |
||||
|
class FixedBodyVisitor : public BodyVisitorBase<StaticVisitor> { |
||||
|
public: |
||||
|
static inline ReturnType Visit(Map* map, HeapObject* object) { |
||||
|
IteratePointers(object, |
||||
|
BodyDescriptor::kStartOffset, |
||||
|
BodyDescriptor::kEndOffset); |
||||
|
return static_cast<ReturnType>(BodyDescriptor::kSize); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// Base class for visitors used for a linear new space iteration.
|
||||
|
// IterateBody returns size of visited object.
|
||||
|
// Certain types of objects (i.e. Code objects) are not handled
|
||||
|
// by dispatch table of this visitor because they cannot appear
|
||||
|
// in the new space.
|
||||
|
//
|
||||
|
// This class is intended to be used in the following way:
|
||||
|
//
|
||||
|
// class SomeVisitor : public StaticNewSpaceVisitor<SomeVisitor> {
|
||||
|
// ...
|
||||
|
// }
|
||||
|
//
|
||||
|
// This is an example of Curiously recurring template pattern
|
||||
|
// (see http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern).
|
||||
|
// We use CRTP to guarantee aggressive compile time optimizations (i.e.
|
||||
|
// inlining and specialization of StaticVisitor::VisitPointers methods).
|
||||
|
template<typename StaticVisitor> |
||||
|
class StaticNewSpaceVisitor : public StaticVisitorBase { |
||||
|
public: |
||||
|
static void Initialize() { |
||||
|
table_.Register(kVisitShortcutCandidate, |
||||
|
&FixedBodyVisitor<StaticVisitor, |
||||
|
ConsString::BodyDescriptor, |
||||
|
int>::Visit); |
||||
|
|
||||
|
table_.Register(kVisitConsString, |
||||
|
&FixedBodyVisitor<StaticVisitor, |
||||
|
ConsString::BodyDescriptor, |
||||
|
int>::Visit); |
||||
|
|
||||
|
table_.Register(kVisitFixedArray, |
||||
|
&FlexibleBodyVisitor<StaticVisitor, |
||||
|
FixedArray::BodyDescriptor, |
||||
|
int>::Visit); |
||||
|
|
||||
|
table_.Register(kVisitByteArray, &VisitByteArray); |
||||
|
|
||||
|
table_.Register(kVisitSharedFunctionInfo, |
||||
|
&FixedBodyVisitor<StaticVisitor, |
||||
|
SharedFunctionInfo::BodyDescriptor, |
||||
|
int>::Visit); |
||||
|
|
||||
|
table_.Register(kVisitSeqAsciiString, &VisitSeqAsciiString); |
||||
|
|
||||
|
table_.Register(kVisitSeqTwoByteString, &VisitSeqTwoByteString); |
||||
|
|
||||
|
table_.RegisterSpecializations<DataObjectVisitor, |
||||
|
kVisitDataObject, |
||||
|
kVisitDataObjectGeneric>(); |
||||
|
table_.RegisterSpecializations<JSObjectVisitor, |
||||
|
kVisitJSObject, |
||||
|
kVisitJSObjectGeneric>(); |
||||
|
table_.RegisterSpecializations<StructVisitor, |
||||
|
kVisitStruct, |
||||
|
kVisitStructGeneric>(); |
||||
|
} |
||||
|
|
||||
|
static inline int IterateBody(Map* map, HeapObject* obj) { |
||||
|
return table_.GetVisitor(map)(map, obj); |
||||
|
} |
||||
|
|
||||
|
static inline void VisitPointers(Object** start, Object** end) { |
||||
|
for (Object** p = start; p < end; p++) StaticVisitor::VisitPointer(p); |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
static inline int VisitByteArray(Map* map, HeapObject* object) { |
||||
|
return reinterpret_cast<ByteArray*>(object)->ByteArraySize(); |
||||
|
} |
||||
|
|
||||
|
static inline int VisitSeqAsciiString(Map* map, HeapObject* object) { |
||||
|
return SeqAsciiString::cast(object)-> |
||||
|
SeqAsciiStringSize(map->instance_type()); |
||||
|
} |
||||
|
|
||||
|
static inline int VisitSeqTwoByteString(Map* map, HeapObject* object) { |
||||
|
return SeqTwoByteString::cast(object)-> |
||||
|
SeqTwoByteStringSize(map->instance_type()); |
||||
|
} |
||||
|
|
||||
|
class DataObjectVisitor { |
||||
|
public: |
||||
|
template<int object_size> |
||||
|
static inline int VisitSpecialized(Map* map, HeapObject* object) { |
||||
|
return object_size; |
||||
|
} |
||||
|
|
||||
|
static inline int Visit(Map* map, HeapObject* object) { |
||||
|
return map->instance_size(); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
typedef FlexibleBodyVisitor<StaticVisitor, |
||||
|
StructBodyDescriptor, |
||||
|
int> StructVisitor; |
||||
|
|
||||
|
typedef FlexibleBodyVisitor<StaticVisitor, |
||||
|
JSObject::BodyDescriptor, |
||||
|
int> JSObjectVisitor; |
||||
|
|
||||
|
typedef int (*Callback)(Map* map, HeapObject* object); |
||||
|
|
||||
|
static VisitorDispatchTable<Callback> table_; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
template<typename StaticVisitor> |
||||
|
VisitorDispatchTable<typename StaticNewSpaceVisitor<StaticVisitor>::Callback> |
||||
|
StaticNewSpaceVisitor<StaticVisitor>::table_; |
||||
|
|
||||
|
|
||||
|
void Code::CodeIterateBody(ObjectVisitor* v) { |
||||
|
int mode_mask = RelocInfo::kCodeTargetMask | |
||||
|
RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) | |
||||
|
RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) | |
||||
|
RelocInfo::ModeMask(RelocInfo::JS_RETURN) | |
||||
|
RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT) | |
||||
|
RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY); |
||||
|
|
||||
|
// Use the relocation info pointer before it is visited by
|
||||
|
// the heap compaction in the next statement.
|
||||
|
RelocIterator it(this, mode_mask); |
||||
|
|
||||
|
IteratePointers(v, |
||||
|
kRelocationInfoOffset, |
||||
|
kRelocationInfoOffset + kPointerSize); |
||||
|
|
||||
|
for (; !it.done(); it.next()) { |
||||
|
it.rinfo()->Visit(v); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
template<typename StaticVisitor> |
||||
|
void Code::CodeIterateBody() { |
||||
|
int mode_mask = RelocInfo::kCodeTargetMask | |
||||
|
RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) | |
||||
|
RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) | |
||||
|
RelocInfo::ModeMask(RelocInfo::JS_RETURN) | |
||||
|
RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT) | |
||||
|
RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY); |
||||
|
|
||||
|
// Use the relocation info pointer before it is visited by
|
||||
|
// the heap compaction in the next statement.
|
||||
|
RelocIterator it(this, mode_mask); |
||||
|
|
||||
|
StaticVisitor::VisitPointer( |
||||
|
reinterpret_cast<Object**>(this->address() + kRelocationInfoOffset)); |
||||
|
|
||||
|
for (; !it.done(); it.next()) { |
||||
|
it.rinfo()->template Visit<StaticVisitor>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} } // namespace v8::internal
|
||||
|
|
||||
|
#endif // V8_OBJECTS_ITERATION_H_
|
@ -0,0 +1,580 @@ |
|||||
|
// 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 platform-specific code. This make the rest of the
|
||||
|
// code less dependent on operating system, compilers and runtime libraries.
|
||||
|
// This module does specifically not deal with differences between different
|
||||
|
// processor architecture.
|
||||
|
// The platform classes have the same definition for all platforms. The
|
||||
|
// implementation for a particular platform is put in platform_<os>.cc.
|
||||
|
// The build system then uses the implementation for the target platform.
|
||||
|
//
|
||||
|
// This design has been chosen because it is simple and fast. Alternatively,
|
||||
|
// the platform dependent classes could have been implemented using abstract
|
||||
|
// superclasses with virtual methods and having specializations for each
|
||||
|
// platform. This design was rejected because it was more complicated and
|
||||
|
// slower. It would require factory methods for selecting the right
|
||||
|
// implementation and the overhead of virtual methods for performance
|
||||
|
// sensitive like mutex locking/unlocking.
|
||||
|
|
||||
|
#ifndef V8_PLATFORM_H_ |
||||
|
#define V8_PLATFORM_H_ |
||||
|
|
||||
|
#define V8_INFINITY INFINITY |
||||
|
|
||||
|
// Windows specific stuff.
|
||||
|
#ifdef WIN32 |
||||
|
|
||||
|
// Microsoft Visual C++ specific stuff.
|
||||
|
#ifdef _MSC_VER |
||||
|
|
||||
|
enum { |
||||
|
FP_NAN, |
||||
|
FP_INFINITE, |
||||
|
FP_ZERO, |
||||
|
FP_SUBNORMAL, |
||||
|
FP_NORMAL |
||||
|
}; |
||||
|
|
||||
|
#undef V8_INFINITY |
||||
|
#define V8_INFINITY HUGE_VAL |
||||
|
|
||||
|
namespace v8 { |
||||
|
namespace internal { |
||||
|
int isfinite(double x); |
||||
|
} } |
||||
|
int isnan(double x); |
||||
|
int isinf(double x); |
||||
|
int isless(double x, double y); |
||||
|
int isgreater(double x, double y); |
||||
|
int fpclassify(double x); |
||||
|
int signbit(double x); |
||||
|
|
||||
|
int strncasecmp(const char* s1, const char* s2, int n); |
||||
|
|
||||
|
#endif // _MSC_VER
|
||||
|
|
||||
|
// Random is missing on both Visual Studio and MinGW.
|
||||
|
int random(); |
||||
|
|
||||
|
#endif // WIN32
|
||||
|
|
||||
|
|
||||
|
#ifdef __sun |
||||
|
# ifndef signbit |
||||
|
int signbit(double x); |
||||
|
# endif |
||||
|
#endif |
||||
|
|
||||
|
|
||||
|
// GCC specific stuff
|
||||
|
#ifdef __GNUC__ |
||||
|
|
||||
|
// Needed for va_list on at least MinGW and Android.
|
||||
|
#include <stdarg.h> |
||||
|
|
||||
|
#define __GNUC_VERSION__ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100) |
||||
|
|
||||
|
// Unfortunately, the INFINITY macro cannot be used with the '-pedantic'
|
||||
|
// warning flag and certain versions of GCC due to a bug:
|
||||
|
// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11931
|
||||
|
// For now, we use the more involved template-based version from <limits>, but
|
||||
|
// only when compiling with GCC versions affected by the bug (2.96.x - 4.0.x)
|
||||
|
// __GNUC_PREREQ is not defined in GCC for Mac OS X, so we define our own macro
|
||||
|
#if __GNUC_VERSION__ >= 29600 && __GNUC_VERSION__ < 40100 |
||||
|
#include <limits> |
||||
|
#undef V8_INFINITY |
||||
|
#define V8_INFINITY std::numeric_limits<double>::infinity() |
||||
|
#endif |
||||
|
|
||||
|
#endif // __GNUC__
|
||||
|
|
||||
|
namespace v8 { |
||||
|
namespace internal { |
||||
|
|
||||
|
// Use AtomicWord for a machine-sized pointer. It is assumed that
|
||||
|
// reads and writes of naturally aligned values of this type are atomic.
|
||||
|
typedef intptr_t AtomicWord; |
||||
|
|
||||
|
class Semaphore; |
||||
|
|
||||
|
double ceiling(double x); |
||||
|
double modulo(double x, double y); |
||||
|
|
||||
|
// Forward declarations.
|
||||
|
class Socket; |
||||
|
|
||||
|
// ----------------------------------------------------------------------------
|
||||
|
// OS
|
||||
|
//
|
||||
|
// This class has static methods for the different platform specific
|
||||
|
// functions. Add methods here to cope with differences between the
|
||||
|
// supported platforms.
|
||||
|
|
||||
|
class OS { |
||||
|
public: |
||||
|
// Initializes the platform OS support. Called once at VM startup.
|
||||
|
static void Setup(); |
||||
|
|
||||
|
// Returns the accumulated user time for thread. This routine
|
||||
|
// can be used for profiling. The implementation should
|
||||
|
// strive for high-precision timer resolution, preferable
|
||||
|
// micro-second resolution.
|
||||
|
static int GetUserTime(uint32_t* secs, uint32_t* usecs); |
||||
|
|
||||
|
// Get a tick counter normalized to one tick per microsecond.
|
||||
|
// Used for calculating time intervals.
|
||||
|
static int64_t Ticks(); |
||||
|
|
||||
|
// Returns current time as the number of milliseconds since
|
||||
|
// 00:00:00 UTC, January 1, 1970.
|
||||
|
static double TimeCurrentMillis(); |
||||
|
|
||||
|
// Returns a string identifying the current time zone. The
|
||||
|
// timestamp is used for determining if DST is in effect.
|
||||
|
static const char* LocalTimezone(double time); |
||||
|
|
||||
|
// Returns the local time offset in milliseconds east of UTC without
|
||||
|
// taking daylight savings time into account.
|
||||
|
static double LocalTimeOffset(); |
||||
|
|
||||
|
// Returns the daylight savings offset for the given time.
|
||||
|
static double DaylightSavingsOffset(double time); |
||||
|
|
||||
|
// Returns last OS error.
|
||||
|
static int GetLastError(); |
||||
|
|
||||
|
static FILE* FOpen(const char* path, const char* mode); |
||||
|
|
||||
|
// Log file open mode is platform-dependent due to line ends issues.
|
||||
|
static const char* LogFileOpenMode; |
||||
|
|
||||
|
// Print output to console. This is mostly used for debugging output.
|
||||
|
// On platforms that has standard terminal output, the output
|
||||
|
// should go to stdout.
|
||||
|
static void Print(const char* format, ...); |
||||
|
static void VPrint(const char* format, va_list args); |
||||
|
|
||||
|
// Print error output to console. This is mostly used for error message
|
||||
|
// output. On platforms that has standard terminal output, the output
|
||||
|
// should go to stderr.
|
||||
|
static void PrintError(const char* format, ...); |
||||
|
static void VPrintError(const char* format, va_list args); |
||||
|
|
||||
|
// Allocate/Free memory used by JS heap. Pages are readable/writable, but
|
||||
|
// they are not guaranteed to be executable unless 'executable' is true.
|
||||
|
// Returns the address of allocated memory, or NULL if failed.
|
||||
|
static void* Allocate(const size_t requested, |
||||
|
size_t* allocated, |
||||
|
bool is_executable); |
||||
|
static void Free(void* address, const size_t size); |
||||
|
// Get the Alignment guaranteed by Allocate().
|
||||
|
static size_t AllocateAlignment(); |
||||
|
|
||||
|
#ifdef ENABLE_HEAP_PROTECTION |
||||
|
// Protect/unprotect a block of memory by marking it read-only/writable.
|
||||
|
static void Protect(void* address, size_t size); |
||||
|
static void Unprotect(void* address, size_t size, bool is_executable); |
||||
|
#endif |
||||
|
|
||||
|
// Returns an indication of whether a pointer is in a space that
|
||||
|
// has been allocated by Allocate(). This method may conservatively
|
||||
|
// always return false, but giving more accurate information may
|
||||
|
// improve the robustness of the stack dump code in the presence of
|
||||
|
// heap corruption.
|
||||
|
static bool IsOutsideAllocatedSpace(void* pointer); |
||||
|
|
||||
|
// Sleep for a number of milliseconds.
|
||||
|
static void Sleep(const int milliseconds); |
||||
|
|
||||
|
// Abort the current process.
|
||||
|
static void Abort(); |
||||
|
|
||||
|
// Debug break.
|
||||
|
static void DebugBreak(); |
||||
|
|
||||
|
// Walk the stack.
|
||||
|
static const int kStackWalkError = -1; |
||||
|
static const int kStackWalkMaxNameLen = 256; |
||||
|
static const int kStackWalkMaxTextLen = 256; |
||||
|
struct StackFrame { |
||||
|
void* address; |
||||
|
char text[kStackWalkMaxTextLen]; |
||||
|
}; |
||||
|
|
||||
|
static int StackWalk(Vector<StackFrame> frames); |
||||
|
|
||||
|
// Factory method for creating platform dependent Mutex.
|
||||
|
// Please use delete to reclaim the storage for the returned Mutex.
|
||||
|
static Mutex* CreateMutex(); |
||||
|
|
||||
|
// Factory method for creating platform dependent Semaphore.
|
||||
|
// Please use delete to reclaim the storage for the returned Semaphore.
|
||||
|
static Semaphore* CreateSemaphore(int count); |
||||
|
|
||||
|
// Factory method for creating platform dependent Socket.
|
||||
|
// Please use delete to reclaim the storage for the returned Socket.
|
||||
|
static Socket* CreateSocket(); |
||||
|
|
||||
|
class MemoryMappedFile { |
||||
|
public: |
||||
|
static MemoryMappedFile* create(const char* name, int size, void* initial); |
||||
|
virtual ~MemoryMappedFile() { } |
||||
|
virtual void* memory() = 0; |
||||
|
}; |
||||
|
|
||||
|
// Safe formatting print. Ensures that str is always null-terminated.
|
||||
|
// Returns the number of chars written, or -1 if output was truncated.
|
||||
|
static int SNPrintF(Vector<char> str, const char* format, ...); |
||||
|
static int VSNPrintF(Vector<char> str, |
||||
|
const char* format, |
||||
|
va_list args); |
||||
|
|
||||
|
static char* StrChr(char* str, int c); |
||||
|
static void StrNCpy(Vector<char> dest, const char* src, size_t n); |
||||
|
|
||||
|
// Support for profiler. Can do nothing, in which case ticks
|
||||
|
// occuring in shared libraries will not be properly accounted
|
||||
|
// for.
|
||||
|
static void LogSharedLibraryAddresses(); |
||||
|
|
||||
|
// The return value indicates the CPU features we are sure of because of the
|
||||
|
// OS. For example MacOSX doesn't run on any x86 CPUs that don't have SSE2
|
||||
|
// instructions.
|
||||
|
// This is a little messy because the interpretation is subject to the cross
|
||||
|
// of the CPU and the OS. The bits in the answer correspond to the bit
|
||||
|
// positions indicated by the members of the CpuFeature enum from globals.h
|
||||
|
static uint64_t CpuFeaturesImpliedByPlatform(); |
||||
|
|
||||
|
// Returns the double constant NAN
|
||||
|
static double nan_value(); |
||||
|
|
||||
|
// Support runtime detection of VFP3 on ARM CPUs.
|
||||
|
static bool ArmCpuHasFeature(CpuFeature feature); |
||||
|
|
||||
|
// Returns the activation frame alignment constraint or zero if
|
||||
|
// the platform doesn't care. Guaranteed to be a power of two.
|
||||
|
static int ActivationFrameAlignment(); |
||||
|
|
||||
|
static void ReleaseStore(volatile AtomicWord* ptr, AtomicWord value); |
||||
|
|
||||
|
private: |
||||
|
static const int msPerSecond = 1000; |
||||
|
|
||||
|
DISALLOW_IMPLICIT_CONSTRUCTORS(OS); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
class VirtualMemory { |
||||
|
public: |
||||
|
// Reserves virtual memory with size.
|
||||
|
explicit VirtualMemory(size_t size); |
||||
|
~VirtualMemory(); |
||||
|
|
||||
|
// Returns whether the memory has been reserved.
|
||||
|
bool IsReserved(); |
||||
|
|
||||
|
// Returns the start address of the reserved memory.
|
||||
|
void* address() { |
||||
|
ASSERT(IsReserved()); |
||||
|
return address_; |
||||
|
}; |
||||
|
|
||||
|
// Returns the size of the reserved memory.
|
||||
|
size_t size() { return size_; } |
||||
|
|
||||
|
// Commits real memory. Returns whether the operation succeeded.
|
||||
|
bool Commit(void* address, size_t size, bool is_executable); |
||||
|
|
||||
|
// Uncommit real memory. Returns whether the operation succeeded.
|
||||
|
bool Uncommit(void* address, size_t size); |
||||
|
|
||||
|
private: |
||||
|
void* address_; // Start address of the virtual memory.
|
||||
|
size_t size_; // Size of the virtual memory.
|
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// ----------------------------------------------------------------------------
|
||||
|
// ThreadHandle
|
||||
|
//
|
||||
|
// A ThreadHandle represents a thread identifier for a thread. The ThreadHandle
|
||||
|
// does not own the underlying os handle. Thread handles can be used for
|
||||
|
// refering to threads and testing equality.
|
||||
|
|
||||
|
class ThreadHandle { |
||||
|
public: |
||||
|
enum Kind { SELF, INVALID }; |
||||
|
explicit ThreadHandle(Kind kind); |
||||
|
|
||||
|
// Destructor.
|
||||
|
~ThreadHandle(); |
||||
|
|
||||
|
// Test for thread running.
|
||||
|
bool IsSelf() const; |
||||
|
|
||||
|
// Test for valid thread handle.
|
||||
|
bool IsValid() const; |
||||
|
|
||||
|
// Get platform-specific data.
|
||||
|
class PlatformData; |
||||
|
PlatformData* thread_handle_data() { return data_; } |
||||
|
|
||||
|
// Initialize the handle to kind
|
||||
|
void Initialize(Kind kind); |
||||
|
|
||||
|
private: |
||||
|
PlatformData* data_; // Captures platform dependent data.
|
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// ----------------------------------------------------------------------------
|
||||
|
// Thread
|
||||
|
//
|
||||
|
// Thread objects are used for creating and running threads. When the start()
|
||||
|
// method is called the new thread starts running the run() method in the new
|
||||
|
// thread. The Thread object should not be deallocated before the thread has
|
||||
|
// terminated.
|
||||
|
|
||||
|
class Thread: public ThreadHandle { |
||||
|
public: |
||||
|
// Opaque data type for thread-local storage keys.
|
||||
|
enum LocalStorageKey {}; |
||||
|
|
||||
|
// Create new thread.
|
||||
|
Thread(); |
||||
|
virtual ~Thread(); |
||||
|
|
||||
|
// Start new thread by calling the Run() method in the new thread.
|
||||
|
void Start(); |
||||
|
|
||||
|
// Wait until thread terminates.
|
||||
|
void Join(); |
||||
|
|
||||
|
// Abstract method for run handler.
|
||||
|
virtual void Run() = 0; |
||||
|
|
||||
|
// Thread-local storage.
|
||||
|
static LocalStorageKey CreateThreadLocalKey(); |
||||
|
static void DeleteThreadLocalKey(LocalStorageKey key); |
||||
|
static void* GetThreadLocal(LocalStorageKey key); |
||||
|
static int GetThreadLocalInt(LocalStorageKey key) { |
||||
|
return static_cast<int>(reinterpret_cast<intptr_t>(GetThreadLocal(key))); |
||||
|
} |
||||
|
static void SetThreadLocal(LocalStorageKey key, void* value); |
||||
|
static void SetThreadLocalInt(LocalStorageKey key, int value) { |
||||
|
SetThreadLocal(key, reinterpret_cast<void*>(static_cast<intptr_t>(value))); |
||||
|
} |
||||
|
static bool HasThreadLocal(LocalStorageKey key) { |
||||
|
return GetThreadLocal(key) != NULL; |
||||
|
} |
||||
|
|
||||
|
// A hint to the scheduler to let another thread run.
|
||||
|
static void YieldCPU(); |
||||
|
|
||||
|
private: |
||||
|
class PlatformData; |
||||
|
PlatformData* data_; |
||||
|
DISALLOW_COPY_AND_ASSIGN(Thread); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// ----------------------------------------------------------------------------
|
||||
|
// Mutex
|
||||
|
//
|
||||
|
// Mutexes are used for serializing access to non-reentrant sections of code.
|
||||
|
// The implementations of mutex should allow for nested/recursive locking.
|
||||
|
|
||||
|
class Mutex { |
||||
|
public: |
||||
|
virtual ~Mutex() {} |
||||
|
|
||||
|
// Locks the given mutex. If the mutex is currently unlocked, it becomes
|
||||
|
// locked and owned by the calling thread, and immediately. If the mutex
|
||||
|
// is already locked by another thread, suspends the calling thread until
|
||||
|
// the mutex is unlocked.
|
||||
|
virtual int Lock() = 0; |
||||
|
|
||||
|
// Unlocks the given mutex. The mutex is assumed to be locked and owned by
|
||||
|
// the calling thread on entrance.
|
||||
|
virtual int Unlock() = 0; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// ----------------------------------------------------------------------------
|
||||
|
// ScopedLock
|
||||
|
//
|
||||
|
// Stack-allocated ScopedLocks provide block-scoped locking and unlocking
|
||||
|
// of a mutex.
|
||||
|
class ScopedLock { |
||||
|
public: |
||||
|
explicit ScopedLock(Mutex* mutex): mutex_(mutex) { |
||||
|
mutex_->Lock(); |
||||
|
} |
||||
|
~ScopedLock() { |
||||
|
mutex_->Unlock(); |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
Mutex* mutex_; |
||||
|
DISALLOW_COPY_AND_ASSIGN(ScopedLock); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// ----------------------------------------------------------------------------
|
||||
|
// Semaphore
|
||||
|
//
|
||||
|
// A semaphore object is a synchronization object that maintains a count. The
|
||||
|
// count is decremented each time a thread completes a wait for the semaphore
|
||||
|
// object and incremented each time a thread signals the semaphore. When the
|
||||
|
// count reaches zero, threads waiting for the semaphore blocks until the
|
||||
|
// count becomes non-zero.
|
||||
|
|
||||
|
class Semaphore { |
||||
|
public: |
||||
|
virtual ~Semaphore() {} |
||||
|
|
||||
|
// Suspends the calling thread until the semaphore counter is non zero
|
||||
|
// and then decrements the semaphore counter.
|
||||
|
virtual void Wait() = 0; |
||||
|
|
||||
|
// Suspends the calling thread until the counter is non zero or the timeout
|
||||
|
// time has passsed. If timeout happens the return value is false and the
|
||||
|
// counter is unchanged. Otherwise the semaphore counter is decremented and
|
||||
|
// true is returned. The timeout value is specified in microseconds.
|
||||
|
virtual bool Wait(int timeout) = 0; |
||||
|
|
||||
|
// Increments the semaphore counter.
|
||||
|
virtual void Signal() = 0; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// ----------------------------------------------------------------------------
|
||||
|
// Socket
|
||||
|
//
|
||||
|
|
||||
|
class Socket { |
||||
|
public: |
||||
|
virtual ~Socket() {} |
||||
|
|
||||
|
// Server initialization.
|
||||
|
virtual bool Bind(const int port) = 0; |
||||
|
virtual bool Listen(int backlog) const = 0; |
||||
|
virtual Socket* Accept() const = 0; |
||||
|
|
||||
|
// Client initialization.
|
||||
|
virtual bool Connect(const char* host, const char* port) = 0; |
||||
|
|
||||
|
// Shutdown socket for both read and write. This causes blocking Send and
|
||||
|
// Receive calls to exit. After Shutdown the Socket object cannot be used for
|
||||
|
// any communication.
|
||||
|
virtual bool Shutdown() = 0; |
||||
|
|
||||
|
// Data Transimission
|
||||
|
virtual int Send(const char* data, int len) const = 0; |
||||
|
virtual int Receive(char* data, int len) const = 0; |
||||
|
|
||||
|
// Set the value of the SO_REUSEADDR socket option.
|
||||
|
virtual bool SetReuseAddress(bool reuse_address) = 0; |
||||
|
|
||||
|
virtual bool IsValid() const = 0; |
||||
|
|
||||
|
static bool Setup(); |
||||
|
static int LastError(); |
||||
|
static uint16_t HToN(uint16_t value); |
||||
|
static uint16_t NToH(uint16_t value); |
||||
|
static uint32_t HToN(uint32_t value); |
||||
|
static uint32_t NToH(uint32_t value); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// ----------------------------------------------------------------------------
|
||||
|
// Sampler
|
||||
|
//
|
||||
|
// A sampler periodically samples the state of the VM and optionally
|
||||
|
// (if used for profiling) the program counter and stack pointer for
|
||||
|
// the thread that created it.
|
||||
|
|
||||
|
// TickSample captures the information collected for each sample.
|
||||
|
class TickSample { |
||||
|
public: |
||||
|
TickSample() |
||||
|
: state(OTHER), |
||||
|
pc(NULL), |
||||
|
sp(NULL), |
||||
|
fp(NULL), |
||||
|
function(NULL), |
||||
|
frames_count(0) {} |
||||
|
StateTag state; // The state of the VM.
|
||||
|
Address pc; // Instruction pointer.
|
||||
|
Address sp; // Stack pointer.
|
||||
|
Address fp; // Frame pointer.
|
||||
|
Address function; // The last called JS function.
|
||||
|
static const int kMaxFramesCount = 64; |
||||
|
Address stack[kMaxFramesCount]; // Call stack.
|
||||
|
int frames_count; // Number of captured frames.
|
||||
|
}; |
||||
|
|
||||
|
#ifdef ENABLE_LOGGING_AND_PROFILING |
||||
|
class Sampler { |
||||
|
public: |
||||
|
// Initialize sampler.
|
||||
|
explicit Sampler(int interval, bool profiling); |
||||
|
virtual ~Sampler(); |
||||
|
|
||||
|
// Performs stack sampling.
|
||||
|
virtual void SampleStack(TickSample* sample) = 0; |
||||
|
|
||||
|
// This method is called for each sampling period with the current
|
||||
|
// program counter.
|
||||
|
virtual void Tick(TickSample* sample) = 0; |
||||
|
|
||||
|
// Start and stop sampler.
|
||||
|
void Start(); |
||||
|
void Stop(); |
||||
|
|
||||
|
// Is the sampler used for profiling.
|
||||
|
inline bool IsProfiling() { return profiling_; } |
||||
|
|
||||
|
// Whether the sampler is running (that is, consumes resources).
|
||||
|
inline bool IsActive() { return active_; } |
||||
|
|
||||
|
class PlatformData; |
||||
|
|
||||
|
private: |
||||
|
const int interval_; |
||||
|
const bool profiling_; |
||||
|
bool active_; |
||||
|
PlatformData* data_; // Platform specific data.
|
||||
|
DISALLOW_IMPLICIT_CONSTRUCTORS(Sampler); |
||||
|
}; |
||||
|
|
||||
|
#endif // ENABLE_LOGGING_AND_PROFILING
|
||||
|
|
||||
|
} } // namespace v8::internal
|
||||
|
|
||||
|
#endif // V8_PLATFORM_H_
|
File diff suppressed because it is too large
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue