summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--V8Binding/Android.v8common.mk1
-rw-r--r--V8Binding/v8/SConstruct75
-rw-r--r--[-rwxr-xr-x]V8Binding/v8/benchmarks/run.html32
-rw-r--r--[-rwxr-xr-x]V8Binding/v8/benchmarks/style.css9
-rw-r--r--V8Binding/v8/include/v8.h27
-rwxr-xr-xV8Binding/v8/src/SConscript2
-rw-r--r--V8Binding/v8/src/api.cc43
-rw-r--r--V8Binding/v8/src/arm/codegen-arm.cc70
-rw-r--r--V8Binding/v8/src/arm/ic-arm.cc18
-rw-r--r--V8Binding/v8/src/arm/macro-assembler-arm.cc2
-rw-r--r--V8Binding/v8/src/arm/register-allocator-arm-inl.h8
-rw-r--r--V8Binding/v8/src/arm/stub-cache-arm.cc6
-rw-r--r--V8Binding/v8/src/bootstrapper.cc14
-rw-r--r--V8Binding/v8/src/compilation-cache.cc2
-rw-r--r--V8Binding/v8/src/debug.cc34
-rw-r--r--V8Binding/v8/src/execution.cc23
-rw-r--r--V8Binding/v8/src/flag-definitions.h3
-rw-r--r--V8Binding/v8/src/frame-element.cc45
-rw-r--r--V8Binding/v8/src/frame-element.h5
-rw-r--r--V8Binding/v8/src/hashmap.cc5
-rw-r--r--V8Binding/v8/src/heap-inl.h25
-rw-r--r--V8Binding/v8/src/heap.cc12
-rw-r--r--V8Binding/v8/src/heap.h25
-rw-r--r--V8Binding/v8/src/ia32/codegen-ia32.cc18
-rw-r--r--V8Binding/v8/src/ia32/ic-ia32.cc38
-rw-r--r--V8Binding/v8/src/ia32/macro-assembler-ia32.cc9
-rw-r--r--V8Binding/v8/src/ia32/regexp-macro-assembler-ia32.cc10
-rw-r--r--V8Binding/v8/src/ia32/register-allocator-ia32-inl.h8
-rw-r--r--V8Binding/v8/src/ia32/stub-cache-ia32.cc6
-rw-r--r--V8Binding/v8/src/ic.cc74
-rw-r--r--V8Binding/v8/src/ic.h8
-rw-r--r--V8Binding/v8/src/interpreter-irregexp.cc8
-rw-r--r--V8Binding/v8/src/log.cc17
-rw-r--r--V8Binding/v8/src/log.h2
-rw-r--r--V8Binding/v8/src/objects-inl.h8
-rw-r--r--V8Binding/v8/src/objects.cc12
-rw-r--r--V8Binding/v8/src/objects.h8
-rw-r--r--V8Binding/v8/src/parser.cc23
-rw-r--r--V8Binding/v8/src/platform-macos.cc17
-rw-r--r--V8Binding/v8/src/register-allocator.cc6
-rw-r--r--V8Binding/v8/src/register-allocator.h5
-rw-r--r--V8Binding/v8/src/rewriter.cc5
-rw-r--r--V8Binding/v8/src/serialize.cc6
-rw-r--r--V8Binding/v8/src/spaces.cc7
-rw-r--r--V8Binding/v8/src/string-stream.cc6
-rw-r--r--V8Binding/v8/src/string-stream.h5
-rw-r--r--V8Binding/v8/src/stub-cache.cc2
-rw-r--r--V8Binding/v8/src/stub-cache.h9
-rw-r--r--V8Binding/v8/src/x64/assembler-x64.cc53
-rw-r--r--V8Binding/v8/src/x64/assembler-x64.h25
-rw-r--r--V8Binding/v8/src/x64/codegen-x64.cc1
-rw-r--r--V8Binding/v8/src/x64/debug-x64.cc15
-rw-r--r--V8Binding/v8/src/x64/disasm-x64.cc663
-rw-r--r--V8Binding/v8/src/x64/ic-x64.cc95
-rw-r--r--V8Binding/v8/src/x64/macro-assembler-x64.cc150
-rw-r--r--V8Binding/v8/src/x64/macro-assembler-x64.h3
-rw-r--r--V8Binding/v8/src/x64/register-allocator-x64-inl.h8
-rw-r--r--V8Binding/v8/src/x64/stub-cache-x64.cc714
-rw-r--r--V8Binding/v8/src/zone.cc5
-rw-r--r--V8Binding/v8/test/cctest/cctest.status10
-rw-r--r--V8Binding/v8/test/cctest/test-api.cc467
-rw-r--r--V8Binding/v8/test/cctest/test-heap.cc2
-rw-r--r--V8Binding/v8/test/cctest/test-mark-compact.cc5
-rw-r--r--V8Binding/v8/test/message/message.status20
-rw-r--r--V8Binding/v8/test/mjsunit/debug-stepin-accessor.js248
-rw-r--r--V8Binding/v8/test/mjsunit/mjsunit.status73
-rw-r--r--V8Binding/v8/test/mjsunit/regexp-call-as-function.js36
-rw-r--r--V8Binding/v8/test/mjsunit/regress/regress-155924.js46
-rw-r--r--V8Binding/v8/test/mjsunit/regress/regress-345.js51
-rw-r--r--V8Binding/v8/test/mjsunit/regress/regress-406.js69
-rw-r--r--V8Binding/v8/test/mjsunit/tools/codemap.js30
-rw-r--r--V8Binding/v8/test/mjsunit/tools/profile.js4
-rw-r--r--V8Binding/v8/test/mjsunit/tools/tickprocessor-test.default25
-rw-r--r--V8Binding/v8/test/mjsunit/tools/tickprocessor-test.ignore-unknown25
-rw-r--r--V8Binding/v8/test/mjsunit/tools/tickprocessor-test.separate-ic29
-rw-r--r--V8Binding/v8/test/mjsunit/tools/tickprocessor.js131
-rw-r--r--V8Binding/v8/test/mozilla/mozilla.status17
-rw-r--r--V8Binding/v8/tools/codemap.js36
-rw-r--r--V8Binding/v8/tools/gyp/v8.gyp1
-rwxr-xr-xV8Binding/v8/tools/mac-nm18
-rwxr-xr-xV8Binding/v8/tools/mac-tick-processor6
-rwxr-xr-xV8Binding/v8/tools/process-heap-prof.py73
-rw-r--r--V8Binding/v8/tools/profile.js18
-rwxr-xr-xV8Binding/v8/tools/test.py1
-rw-r--r--V8Binding/v8/tools/tickprocessor-driver.js8
-rw-r--r--V8Binding/v8/tools/tickprocessor.js65
-rw-r--r--V8Binding/v8/tools/v8.xcodeproj/project.pbxproj8
-rw-r--r--V8Binding/v8/tools/visual_studio/v8_base.vcproj12
-rw-r--r--V8Binding/v8/tools/visual_studio/v8_base_arm.vcproj8
-rw-r--r--WEBKIT_MERGE_REVISION2
-rw-r--r--WebCore/platform/SharedBuffer.h11
91 files changed, 3194 insertions, 896 deletions
diff --git a/V8Binding/Android.v8common.mk b/V8Binding/Android.v8common.mk
index bf2e796..4da3a30 100644
--- a/V8Binding/Android.v8common.mk
+++ b/V8Binding/Android.v8common.mk
@@ -21,6 +21,7 @@ V8_LOCAL_SRC_FILES := \
src/execution.cc \
src/factory.cc \
src/flags.cc \
+ src/frame-element.cc \
src/frames.cc \
src/func-name-inferrer.cc \
src/global-handles.cc \
diff --git a/V8Binding/v8/SConstruct b/V8Binding/v8/SConstruct
index 78b050d..dbcd616 100644
--- a/V8Binding/v8/SConstruct
+++ b/V8Binding/v8/SConstruct
@@ -149,31 +149,22 @@ LIBRARY_FLAGS = {
'-Wstrict-aliasing=2'],
'CPPPATH': ANDROID_INCLUDES,
},
- 'wordsize:32': {
- 'arch:x64': {
- 'CCFLAGS': ['-m64'],
- 'LINKFLAGS': ['-m64']
- }
- },
- 'wordsize:64': {
- 'arch:ia32': {
- 'CCFLAGS': ['-m32'],
- 'LINKFLAGS': ['-m32']
- },
- 'arch:arm': {
- 'CCFLAGS': ['-m32'],
- 'LINKFLAGS': ['-m32']
- }
- },
'arch:ia32': {
- 'CPPDEFINES': ['V8_TARGET_ARCH_IA32']
+ 'CPPDEFINES': ['V8_TARGET_ARCH_IA32'],
+ 'CCFLAGS': ['-m32'],
+ 'LINKFLAGS': ['-m32']
},
'arch:arm': {
'CPPDEFINES': ['V8_TARGET_ARCH_ARM']
},
+ 'simulator:arm': {
+ 'CCFLAGS': ['-m32'],
+ 'LINKFLAGS': ['-m32']
+ },
'arch:x64': {
- 'CCFLAGS': ['-fno-strict-aliasing'],
- 'CPPDEFINES': ['V8_TARGET_ARCH_X64']
+ 'CPPDEFINES': ['V8_TARGET_ARCH_X64'],
+ 'CCFLAGS': ['-fno-strict-aliasing', '-m64'],
+ 'LINKFLAGS': ['-m64'],
},
'prof:oprofile': {
'CPPDEFINES': ['ENABLE_OPROFILE_AGENT']
@@ -341,22 +332,6 @@ CCTEST_EXTRA_FLAGS = {
'CPPDEFINES': ['SK_RELEASE', 'NDEBUG']
}
},
- 'wordsize:32': {
- 'arch:x64': {
- 'CCFLAGS': ['-m64'],
- 'LINKFLAGS': ['-m64']
- }
- },
- 'wordsize:64': {
- 'arch:ia32': {
- 'CCFLAGS': ['-m32'],
- 'LINKFLAGS': ['-m32']
- },
- 'arch:arm': {
- 'CCFLAGS': ['-m32'],
- 'LINKFLAGS': ['-m32']
- }
- }
},
'msvc': {
'all': {
@@ -408,21 +383,17 @@ SAMPLE_FLAGS = {
'CPPDEFINES': ['SK_RELEASE', 'NDEBUG']
}
},
- 'wordsize:32': {
- 'arch:x64': {
- 'CCFLAGS': ['-m64'],
- 'LINKFLAGS': ['-m64']
- }
+ 'arch:ia32': {
+ 'CCFLAGS': ['-m32'],
+ 'LINKFLAGS': ['-m32']
},
- 'wordsize:64': {
- 'arch:ia32': {
- 'CCFLAGS': ['-m32'],
- 'LINKFLAGS': ['-m32']
- },
- 'arch:arm': {
- 'CCFLAGS': ['-m32'],
- 'LINKFLAGS': ['-m32']
- }
+ 'arch:x64': {
+ 'CCFLAGS': ['-m64'],
+ 'LINKFLAGS': ['-m64']
+ },
+ 'simulator:arm': {
+ 'CCFLAGS': ['-m32'],
+ 'LINKFLAGS': ['-m32']
},
'mode:release': {
'CCFLAGS': ['-O2']
@@ -533,7 +504,6 @@ def GuessToolchain(os):
OS_GUESS = utils.GuessOS()
TOOLCHAIN_GUESS = GuessToolchain(OS_GUESS)
ARCH_GUESS = utils.GuessArchitecture()
-WORDSIZE_GUESS = utils.GuessWordsize()
SIMPLE_OPTIONS = {
@@ -587,11 +557,6 @@ SIMPLE_OPTIONS = {
'default': 'on',
'help': 'use Microsoft Visual C++ link-time code generation'
},
- 'wordsize': {
- 'values': ['64', '32'],
- 'default': WORDSIZE_GUESS,
- 'help': 'the word size'
- },
'simulator': {
'values': ['arm', 'none'],
'default': 'none',
diff --git a/V8Binding/v8/benchmarks/run.html b/V8Binding/v8/benchmarks/run.html
index 050764e..ef2c186 100755..100644
--- a/V8Binding/v8/benchmarks/run.html
+++ b/V8Binding/v8/benchmarks/run.html
@@ -55,9 +55,35 @@ function Run() {
NotifyScore: AddScore });
}
+function ShowWarningIfObsolete() {
+ // If anything goes wrong we will just catch the exception and no
+ // warning is shown, i.e., no harm is done.
+ try {
+ var xmlhttp;
+ var next_version = parseInt(BenchmarkSuite.version) + 1;
+ var next_version_url = "../v" + next_version + "/run.html";
+ if (window.XMLHttpRequest) {
+ xmlhttp = new window.XMLHttpRequest();
+ } else if (window.ActiveXObject) {
+ xmlhttp = new window.ActiveXObject("Microsoft.XMLHTTP");
+ }
+ xmlhttp.open('GET', next_version_url, true);
+ xmlhttp.onreadystatechange = function() {
+ if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
+ document.getElementById('obsolete').style.display="block";
+ }
+ };
+ xmlhttp.send(null);
+ } catch(e) {
+ // Ignore exception if check for next version fails.
+ // Hence no warning is displayed.
+ }
+}
+
function Load() {
var version = BenchmarkSuite.version;
document.getElementById("version").innerHTML = version;
+ ShowWarningIfObsolete();
setTimeout(Run, 200);
}
</script>
@@ -65,6 +91,12 @@ function Load() {
<body onload="Load()">
<div>
<div class="title"><h1>V8 Benchmark Suite - version <span id="version">?</span></h1></div>
+ <div class="warning" id="obsolete">
+Warning! This is not the latest version of the V8 benchmark
+suite. Consider running the
+<a href="http://v8.googlecode.com/svn/data/benchmarks/current/run.html">
+latest version</a>.
+ </div>
<table>
<tr>
<td class="contents">
diff --git a/V8Binding/v8/benchmarks/style.css b/V8Binding/v8/benchmarks/style.css
index 46320c1..d9f4dbf 100755..100644
--- a/V8Binding/v8/benchmarks/style.css
+++ b/V8Binding/v8/benchmarks/style.css
@@ -55,6 +55,15 @@ div.run {
border: 1px solid rgb(51, 102, 204);
}
+div.warning {
+ background: #ffffd9;
+ border: 1px solid #d2d26a;
+ display: none;
+ margin: 1em 0 2em;
+ padding: 8px;
+ text-align: center;
+}
+
#status {
text-align: center;
margin-top: 50px;
diff --git a/V8Binding/v8/include/v8.h b/V8Binding/v8/include/v8.h
index 8f22c81..cf8a3bf 100644
--- a/V8Binding/v8/include/v8.h
+++ b/V8Binding/v8/include/v8.h
@@ -180,7 +180,7 @@ template <class T> class V8EXPORT_INLINE Handle {
/**
* Creates an empty handle.
*/
- Handle();
+ inline Handle();
/**
* Creates a new handle for the specified value.
@@ -264,7 +264,7 @@ template <class T> class V8EXPORT_INLINE Handle {
*/
template <class T> class V8EXPORT_INLINE Local : public Handle<T> {
public:
- Local();
+ inline Local();
template <class S> inline Local(Local<S> that)
: Handle<T>(reinterpret_cast<T*>(*that)) {
/**
@@ -284,7 +284,7 @@ template <class T> class V8EXPORT_INLINE Local : public Handle<T> {
* The referee is kept alive by the local handle even when
* the original handle is destroyed/disposed.
*/
- static Local<T> New(Handle<T> that);
+ inline static Local<T> New(Handle<T> that);
};
@@ -312,7 +312,7 @@ template <class T> class V8EXPORT_INLINE Persistent : public Handle<T> {
* Creates an empty persistent handle that doesn't point to any
* storage cell.
*/
- Persistent();
+ inline Persistent();
/**
* Creates a persistent handle for the same storage cell as the
@@ -353,7 +353,7 @@ template <class T> class V8EXPORT_INLINE Persistent : public Handle<T> {
* Creates a new persistent handle for an existing local or
* persistent handle.
*/
- static Persistent<T> New(Handle<T> that);
+ inline static Persistent<T> New(Handle<T> that);
/**
* Releases the storage cell referenced by this persistent handle.
@@ -361,7 +361,7 @@ template <class T> class V8EXPORT_INLINE Persistent : public Handle<T> {
* This handle's reference, and any any other references to the storage
* cell remain and IsEmpty will still return false.
*/
- void Dispose();
+ inline void Dispose();
/**
* Make the reference to this object weak. When only weak handles
@@ -369,20 +369,20 @@ template <class T> class V8EXPORT_INLINE Persistent : public Handle<T> {
* callback to the given V8::WeakReferenceCallback function, passing
* it the object reference and the given parameters.
*/
- void MakeWeak(void* parameters, WeakReferenceCallback callback);
+ inline void MakeWeak(void* parameters, WeakReferenceCallback callback);
/** Clears the weak reference to this object.*/
- void ClearWeak();
+ inline void ClearWeak();
/**
*Checks if the handle holds the only reference to an object.
*/
- bool IsNearDeath() const;
+ inline bool IsNearDeath() const;
/**
* Returns true if the handle's reference is weak.
*/
- bool IsWeak() const;
+ inline bool IsWeak() const;
private:
friend class ImplementationUtilities;
@@ -1113,6 +1113,13 @@ class V8EXPORT Object : public Value {
/** Sets the value in an internal field. */
void SetInternalField(int index, Handle<Value> value);
+ // The two functions below do not perform index bounds checks and
+ // they do not check that the VM is still running. Use with caution.
+ /** Gets a native pointer from an internal field. */
+ void* GetPointerFromInternalField(int index);
+ /** Sets a native pointer in an internal field. */
+ void SetPointerInInternalField(int index, void* value);
+
// Testers for local properties.
bool HasRealNamedProperty(Handle<String> key);
bool HasRealIndexedProperty(uint32_t index);
diff --git a/V8Binding/v8/src/SConscript b/V8Binding/v8/src/SConscript
index f1ca875..f9f9634 100755
--- a/V8Binding/v8/src/SConscript
+++ b/V8Binding/v8/src/SConscript
@@ -40,7 +40,7 @@ SOURCES = {
'codegen.cc', 'compilation-cache.cc', 'compiler.cc', 'contexts.cc',
'conversions.cc', 'counters.cc', 'dateparser.cc', 'debug.cc',
'debug-agent.cc', 'disassembler.cc', 'execution.cc', 'factory.cc',
- 'flags.cc', 'frames.cc', 'func-name-inferrer.cc',
+ 'flags.cc', 'frame-element.cc', 'frames.cc', 'func-name-inferrer.cc',
'global-handles.cc', 'handles.cc', 'hashmap.cc',
'heap.cc', 'ic.cc', 'interpreter-irregexp.cc', 'jsregexp.cc',
'jump-target.cc', 'log.cc', 'log-utils.cc', 'mark-compact.cc', 'messages.cc',
diff --git a/V8Binding/v8/src/api.cc b/V8Binding/v8/src/api.cc
index 3eab87a..9e3ca9b 100644
--- a/V8Binding/v8/src/api.cc
+++ b/V8Binding/v8/src/api.cc
@@ -2465,6 +2465,44 @@ void v8::Object::SetInternalField(int index, v8::Handle<Value> value) {
}
+void* v8::Object::GetPointerFromInternalField(int index) {
+ i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
+ i::Object* pointer = obj->GetInternalField(index);
+ if (pointer->IsSmi()) {
+ // Fast case, aligned native pointer.
+ return pointer;
+ }
+
+ // Read from uninitialized field.
+ if (!pointer->IsProxy()) {
+ // Play safe even if it's something unexpected.
+ ASSERT(pointer->IsUndefined());
+ return NULL;
+ }
+
+ // Unaligned native pointer.
+ return reinterpret_cast<void*>(i::Proxy::cast(pointer)->proxy());
+}
+
+
+void v8::Object::SetPointerInInternalField(int index, void* value) {
+ i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
+ i::Object* as_object = reinterpret_cast<i::Object*>(value);
+ if (as_object->IsSmi()) {
+ // Aligned pointer, store as is.
+ obj->SetInternalField(index, as_object);
+ } else {
+ // Currently internal fields are used by DOM wrappers which only
+ // get garbage collected by the mark-sweep collector, so we
+ // pretenure the proxy.
+ HandleScope scope;
+ i::Handle<i::Proxy> proxy =
+ i::Factory::NewProxy(reinterpret_cast<i::Address>(value), i::TENURED);
+ if (!proxy.is_null()) obj->SetInternalField(index, *proxy);
+ }
+}
+
+
// --- E n v i r o n m e n t ---
bool v8::V8::Initialize() {
@@ -2516,13 +2554,8 @@ Persistent<Context> v8::Context::New(
i::Handle<i::Context> env;
{
ENTER_V8;
-#if defined(ANDROID)
- // Avoid exact work when creating new context. Android has its
- // own onLowMemory notification.
-#else
// Give the heap a chance to cleanup if we've disposed contexts.
i::Heap::CollectAllGarbageIfContextDisposed();
-#endif
v8::Handle<ObjectTemplate> proxy_template = global_template;
i::Handle<i::FunctionTemplateInfo> proxy_constructor;
diff --git a/V8Binding/v8/src/arm/codegen-arm.cc b/V8Binding/v8/src/arm/codegen-arm.cc
index 3f7ccf5..5f8149e 100644
--- a/V8Binding/v8/src/arm/codegen-arm.cc
+++ b/V8Binding/v8/src/arm/codegen-arm.cc
@@ -2897,7 +2897,7 @@ void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
__ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
// Write to the indexed properties array.
- int offset = i * kPointerSize + Array::kHeaderSize;
+ int offset = i * kPointerSize + FixedArray::kHeaderSize;
__ str(r0, FieldMemOperand(r1, offset));
// Update the write barrier for the array address.
@@ -3737,7 +3737,8 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
}
frame_->EmitPush(r0); // r0 has result
}
- ASSERT((has_cc() && frame_->height() == original_height) ||
+ ASSERT(!has_valid_frame() ||
+ (has_cc() && frame_->height() == original_height) ||
(!has_cc() && frame_->height() == original_height + 1));
}
@@ -3871,22 +3872,12 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
&is_true,
false_target(),
false);
- if (has_cc()) {
- Branch(false, false_target());
-
- // Evaluate right side expression.
- is_true.Bind();
- LoadConditionAndSpill(node->right(),
- NOT_INSIDE_TYPEOF,
- true_target(),
- false_target(),
- false);
-
- } else {
+ if (has_valid_frame() && !has_cc()) {
+ // The left-hand side result is on top of the virtual frame.
JumpTarget pop_and_continue;
JumpTarget exit;
- __ ldr(r0, frame_->Top()); // dup the stack top
+ __ ldr(r0, frame_->Top()); // Duplicate the stack top.
frame_->EmitPush(r0);
// Avoid popping the result if it converts to 'false' using the
// standard ToBoolean() conversion as described in ECMA-262,
@@ -3904,6 +3895,22 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
// Exit (always with a materialized value).
exit.Bind();
+ } else if (has_cc() || is_true.is_linked()) {
+ // The left-hand side is either (a) partially compiled to
+ // control flow with a final branch left to emit or (b) fully
+ // compiled to control flow and possibly true.
+ if (has_cc()) {
+ Branch(false, false_target());
+ }
+ is_true.Bind();
+ LoadConditionAndSpill(node->right(),
+ NOT_INSIDE_TYPEOF,
+ true_target(),
+ false_target(),
+ false);
+ } else {
+ // Nothing to do.
+ ASSERT(!has_valid_frame() && !has_cc() && !is_true.is_linked());
}
} else if (op == Token::OR) {
@@ -3913,18 +3920,8 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
true_target(),
&is_false,
false);
- if (has_cc()) {
- Branch(true, true_target());
-
- // Evaluate right side expression.
- is_false.Bind();
- LoadConditionAndSpill(node->right(),
- NOT_INSIDE_TYPEOF,
- true_target(),
- false_target(),
- false);
-
- } else {
+ if (has_valid_frame() && !has_cc()) {
+ // The left-hand side result is on top of the virtual frame.
JumpTarget pop_and_continue;
JumpTarget exit;
@@ -3946,6 +3943,22 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
// Exit (always with a materialized value).
exit.Bind();
+ } else if (has_cc() || is_false.is_linked()) {
+ // The left-hand side is either (a) partially compiled to
+ // control flow with a final branch left to emit or (b) fully
+ // compiled to control flow and possibly false.
+ if (has_cc()) {
+ Branch(true, true_target());
+ }
+ is_false.Bind();
+ LoadConditionAndSpill(node->right(),
+ NOT_INSIDE_TYPEOF,
+ true_target(),
+ false_target(),
+ false);
+ } else {
+ // Nothing to do.
+ ASSERT(!has_valid_frame() && !has_cc() && !is_false.is_linked());
}
} else {
@@ -3989,7 +4002,8 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
}
frame_->EmitPush(r0);
}
- ASSERT((has_cc() && frame_->height() == original_height) ||
+ ASSERT(!has_valid_frame() ||
+ (has_cc() && frame_->height() == original_height) ||
(!has_cc() && frame_->height() == original_height + 1));
}
diff --git a/V8Binding/v8/src/arm/ic-arm.cc b/V8Binding/v8/src/arm/ic-arm.cc
index b436760..82a2bec 100644
--- a/V8Binding/v8/src/arm/ic-arm.cc
+++ b/V8Binding/v8/src/arm/ic-arm.cc
@@ -91,14 +91,14 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
__ b(ne, miss);
// Compute the capacity mask.
- const int kCapacityOffset =
- Array::kHeaderSize + StringDictionary::kCapacityIndex * kPointerSize;
+ const int kCapacityOffset = StringDictionary::kHeaderSize +
+ StringDictionary::kCapacityIndex * kPointerSize;
__ ldr(r3, FieldMemOperand(t0, kCapacityOffset));
__ mov(r3, Operand(r3, ASR, kSmiTagSize)); // convert smi to int
__ sub(r3, r3, Operand(1));
- const int kElementsStartOffset =
- Array::kHeaderSize + StringDictionary::kElementsStartIndex * kPointerSize;
+ const int kElementsStartOffset = StringDictionary::kHeaderSize +
+ StringDictionary::kElementsStartIndex * kPointerSize;
// Generate an unrolled loop that performs a few probes before
// giving up. Measurements done on Gmail indicate that 2 probes
@@ -599,7 +599,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
// Fast case: Do the load.
__ bind(&fast);
- __ add(r3, r1, Operand(Array::kHeaderSize - kHeapObjectTag));
+ __ add(r3, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ ldr(r0, MemOperand(r3, r0, LSL, kPointerSizeLog2));
__ cmp(r0, Operand(Factory::the_hole_value()));
// In case the loaded value is the_hole we have to consult GetProperty
@@ -666,9 +666,9 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
// Untag the key (for checking against untagged length in the fixed array).
__ mov(r1, Operand(r1, ASR, kSmiTagSize));
// Compute address to store into and check array bounds.
- __ add(r2, r3, Operand(Array::kHeaderSize - kHeapObjectTag));
+ __ add(r2, r3, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2));
- __ ldr(ip, FieldMemOperand(r3, Array::kLengthOffset));
+ __ ldr(ip, FieldMemOperand(r3, FixedArray::kLengthOffset));
__ cmp(r1, Operand(ip));
__ b(lo, &fast);
@@ -696,7 +696,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
__ mov(r3, Operand(r2));
// NOTE: Computing the address to store into must take the fact
// that the key has been incremented into account.
- int displacement = Array::kHeaderSize - kHeapObjectTag -
+ int displacement = FixedArray::kHeaderSize - kHeapObjectTag -
((1 << kSmiTagSize) * 2);
__ add(r2, r2, Operand(displacement));
__ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
@@ -721,7 +721,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
__ cmp(r1, Operand(ip));
__ b(hs, &extra);
__ mov(r3, Operand(r2));
- __ add(r2, r2, Operand(Array::kHeaderSize - kHeapObjectTag));
+ __ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
diff --git a/V8Binding/v8/src/arm/macro-assembler-arm.cc b/V8Binding/v8/src/arm/macro-assembler-arm.cc
index 47e2749..875c91e 100644
--- a/V8Binding/v8/src/arm/macro-assembler-arm.cc
+++ b/V8Binding/v8/src/arm/macro-assembler-arm.cc
@@ -226,7 +226,7 @@ void MacroAssembler::RecordWrite(Register object, Register offset,
// Add the page header (including remembered set), array header, and array
// body size to the page address.
add(object, object, Operand(Page::kObjectStartOffset
- + Array::kHeaderSize));
+ + FixedArray::kHeaderSize));
add(object, object, Operand(scratch));
bind(&fast);
diff --git a/V8Binding/v8/src/arm/register-allocator-arm-inl.h b/V8Binding/v8/src/arm/register-allocator-arm-inl.h
index d98818f..4691f29 100644
--- a/V8Binding/v8/src/arm/register-allocator-arm-inl.h
+++ b/V8Binding/v8/src/arm/register-allocator-arm-inl.h
@@ -60,7 +60,7 @@ bool RegisterAllocator::IsReserved(Register reg) {
int RegisterAllocator::ToNumber(Register reg) {
ASSERT(reg.is_valid() && !IsReserved(reg));
- static int numbers[] = {
+ const int kNumbers[] = {
0, // r0
1, // r1
2, // r2
@@ -78,15 +78,15 @@ int RegisterAllocator::ToNumber(Register reg) {
11, // lr
-1 // pc
};
- return numbers[reg.code()];
+ return kNumbers[reg.code()];
}
Register RegisterAllocator::ToRegister(int num) {
ASSERT(num >= 0 && num < kNumRegisters);
- static Register registers[] =
+ const Register kRegisters[] =
{ r0, r1, r2, r3, r4, r5, r6, r7, r9, r10, ip, lr };
- return registers[num];
+ return kRegisters[num];
}
diff --git a/V8Binding/v8/src/arm/stub-cache-arm.cc b/V8Binding/v8/src/arm/stub-cache-arm.cc
index 6d9ace8..d6650c9 100644
--- a/V8Binding/v8/src/arm/stub-cache-arm.cc
+++ b/V8Binding/v8/src/arm/stub-cache-arm.cc
@@ -164,7 +164,7 @@ void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
__ ldr(dst, FieldMemOperand(src, offset));
} else {
// Calculate the offset into the properties array.
- int offset = index * kPointerSize + Array::kHeaderSize;
+ int offset = index * kPointerSize + FixedArray::kHeaderSize;
__ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
__ ldr(dst, FieldMemOperand(dst, offset));
}
@@ -330,7 +330,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
__ RecordWrite(receiver_reg, name_reg, scratch);
} else {
// Write to the properties array.
- int offset = index * kPointerSize + Array::kHeaderSize;
+ int offset = index * kPointerSize + FixedArray::kHeaderSize;
// Get the properties array
__ ldr(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
__ str(r0, FieldMemOperand(scratch, offset));
@@ -1121,8 +1121,6 @@ Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
}
-// TODO(1224671): IC stubs for keyed loads have not been implemented
-// for ARM.
Object* KeyedLoadStubCompiler::CompileLoadField(String* name,
JSObject* receiver,
JSObject* holder,
diff --git a/V8Binding/v8/src/bootstrapper.cc b/V8Binding/v8/src/bootstrapper.cc
index ad5396e..a2c4562 100644
--- a/V8Binding/v8/src/bootstrapper.cc
+++ b/V8Binding/v8/src/bootstrapper.cc
@@ -47,14 +47,10 @@ namespace internal {
// generate an index for each native JS file.
class SourceCodeCache BASE_EMBEDDED {
public:
- explicit SourceCodeCache(Script::Type type): type_(type) { }
+ explicit SourceCodeCache(Script::Type type): type_(type), cache_(NULL) { }
void Initialize(bool create_heap_objects) {
- if (create_heap_objects) {
- cache_ = Heap::empty_fixed_array();
- } else {
- cache_ = NULL;
- }
+ cache_ = create_heap_objects ? Heap::empty_fixed_array() : NULL;
}
void Iterate(ObjectVisitor* v) {
@@ -1107,12 +1103,6 @@ bool Genesis::InstallNatives() {
global_context()->set_empty_script(*script);
}
-#ifdef V8_HOST_ARCH_64_BIT
- // TODO(X64): Remove this when inline caches work.
- FLAG_use_ic = false;
-#endif // V8_HOST_ARCH_64_BIT
-
-
if (FLAG_natives_file == NULL) {
// Without natives file, install default natives.
for (int i = Natives::GetDelayCount();
diff --git a/V8Binding/v8/src/compilation-cache.cc b/V8Binding/v8/src/compilation-cache.cc
index 64af075..ec5b39c 100644
--- a/V8Binding/v8/src/compilation-cache.cc
+++ b/V8Binding/v8/src/compilation-cache.cc
@@ -63,6 +63,8 @@ class CompilationSubCache {
tables_ = NewArray<Object*>(generations);
}
+ ~CompilationSubCache() { DeleteArray(tables_); }
+
// Get the compilation cache tables for a specific generation.
Handle<CompilationCacheTable> GetTable(int generation);
diff --git a/V8Binding/v8/src/debug.cc b/V8Binding/v8/src/debug.cc
index 52be930..64f98c7 100644
--- a/V8Binding/v8/src/debug.cc
+++ b/V8Binding/v8/src/debug.cc
@@ -334,8 +334,11 @@ void BreakLocationIterator::PrepareStepIn() {
rinfo()->set_target_address(stub->entry());
}
} else {
- // Step in through constructs call requires no changes to the running code.
- ASSERT(RelocInfo::IsConstructCall(rmode()));
+ // Step in through construct call requires no changes to the running code.
+ // Step in through getters/setters should already be prepared as well
+ // because caller of this function (Debug::PrepareStep) is expected to
+ // flood the top frame's function with one shot breakpoints.
+ ASSERT(RelocInfo::IsConstructCall(rmode()) || code->is_inline_cache_stub());
}
}
@@ -1087,10 +1090,18 @@ void Debug::PrepareStep(StepAction step_action, int step_count) {
// Compute whether or not the target is a call target.
bool is_call_target = false;
+ bool is_load_or_store = false;
+ bool is_inline_cache_stub = false;
if (RelocInfo::IsCodeTarget(it.rinfo()->rmode())) {
Address target = it.rinfo()->target_address();
Code* code = Code::GetCodeFromTargetAddress(target);
- if (code->is_call_stub()) is_call_target = true;
+ if (code->is_call_stub()) {
+ is_call_target = true;
+ }
+ if (code->is_inline_cache_stub()) {
+ is_inline_cache_stub = true;
+ is_load_or_store = !is_call_target;
+ }
}
// If this is the last break code target step out is the only possibility.
@@ -1103,8 +1114,8 @@ void Debug::PrepareStep(StepAction step_action, int step_count) {
JSFunction* function = JSFunction::cast(frames_it.frame()->function());
FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
}
- } else if (!(is_call_target || RelocInfo::IsConstructCall(it.rmode())) ||
- step_action == StepNext || step_action == StepMin) {
+ } else if (!(is_inline_cache_stub || RelocInfo::IsConstructCall(it.rmode()))
+ || step_action == StepNext || step_action == StepMin) {
// Step next or step min.
// Fill the current function with one-shot break points.
@@ -1117,9 +1128,20 @@ void Debug::PrepareStep(StepAction step_action, int step_count) {
} else {
// Fill the current function with one-shot break points even for step in on
// a call target as the function called might be a native function for
- // which step in will not stop.
+ // which step in will not stop. It also prepares for stepping in
+ // getters/setters.
FloodWithOneShot(shared);
+ if (is_load_or_store) {
+ // Remember source position and frame to handle step in getter/setter. If
+ // there is a custom getter/setter it will be handled in
+ // Object::Get/SetPropertyWithCallback, otherwise the step action will be
+ // propagated on the next Debug::Break.
+ thread_local_.last_statement_position_ =
+ debug_info->code()->SourceStatementPosition(frame->pc());
+ thread_local_.last_fp_ = frame->fp();
+ }
+
// Step in or Step in min
it.PrepareStepIn();
ActivateStepIn(frame);
diff --git a/V8Binding/v8/src/execution.cc b/V8Binding/v8/src/execution.cc
index adc1872..40a9b4f 100644
--- a/V8Binding/v8/src/execution.cc
+++ b/V8Binding/v8/src/execution.cc
@@ -164,19 +164,16 @@ Handle<Object> Execution::GetFunctionDelegate(Handle<Object> object) {
// If you return a function from here, it will be called when an
// attempt is made to call the given object as a function.
- // The regular expression code here is really meant more as an
- // example than anything else. KJS does not support calling regular
- // expressions as functions, but SpiderMonkey does.
- if (FLAG_call_regexp) {
- bool is_regexp =
- object->IsHeapObject() &&
- (HeapObject::cast(*object)->map()->constructor() ==
- *Top::regexp_function());
-
- if (is_regexp) {
- Handle<String> exec = Factory::exec_symbol();
- return Handle<Object>(object->GetProperty(*exec));
- }
+ // Regular expressions can be called as functions in both Firefox
+ // and Safari so we allow it too.
+ bool is_regexp =
+ object->IsHeapObject() &&
+ (HeapObject::cast(*object)->map()->constructor() ==
+ *Top::regexp_function());
+
+ if (is_regexp) {
+ Handle<String> exec = Factory::exec_symbol();
+ return Handle<Object>(object->GetProperty(*exec));
}
// Objects created through the API can have an instance-call handler
diff --git a/V8Binding/v8/src/flag-definitions.h b/V8Binding/v8/src/flag-definitions.h
index 4e7829b..b0770b0 100644
--- a/V8Binding/v8/src/flag-definitions.h
+++ b/V8Binding/v8/src/flag-definitions.h
@@ -144,9 +144,6 @@ DEFINE_bool(debugger_auto_break, false,
"automatically set the debug break flag when debugger commands are "
"in the queue (experimental)")
-// execution.cc
-DEFINE_bool(call_regexp, false, "allow calls to RegExp objects")
-
// frames.cc
DEFINE_int(max_stack_trace_source_length, 300,
"maximum length of function source code printed in a stack trace.")
diff --git a/V8Binding/v8/src/frame-element.cc b/V8Binding/v8/src/frame-element.cc
new file mode 100644
index 0000000..e6bc2ea
--- /dev/null
+++ b/V8Binding/v8/src/frame-element.cc
@@ -0,0 +1,45 @@
+// 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 "frame-element.h"
+
+namespace v8 {
+namespace internal {
+
+// -------------------------------------------------------------------------
+// FrameElement implementation.
+
+
+FrameElement::ZoneObjectList* FrameElement::ConstantList() {
+ static ZoneObjectList list(10);
+ return &list;
+}
+
+
+} } // namespace v8::internal
diff --git a/V8Binding/v8/src/frame-element.h b/V8Binding/v8/src/frame-element.h
index 666aabb..ccdecf1 100644
--- a/V8Binding/v8/src/frame-element.h
+++ b/V8Binding/v8/src/frame-element.h
@@ -91,10 +91,7 @@ class FrameElement BASE_EMBEDDED {
// this table of handles to the actual constants.
typedef ZoneList<Handle<Object> > ZoneObjectList;
- static ZoneObjectList* ConstantList() {
- static ZoneObjectList list(10);
- return &list;
- }
+ static ZoneObjectList* ConstantList();
// Clear the constants indirection table.
static void ClearConstantList() {
diff --git a/V8Binding/v8/src/hashmap.cc b/V8Binding/v8/src/hashmap.cc
index b717312..3c4e5cd 100644
--- a/V8Binding/v8/src/hashmap.cc
+++ b/V8Binding/v8/src/hashmap.cc
@@ -194,7 +194,10 @@ HashMap::Entry* HashMap::Probe(void* key, uint32_t hash) {
void HashMap::Initialize(uint32_t capacity) {
ASSERT(IsPowerOf2(capacity));
map_ = reinterpret_cast<Entry*>(allocator_->New(capacity * sizeof(Entry)));
- if (map_ == NULL) V8::FatalProcessOutOfMemory("HashMap::Initialize");
+ if (map_ == NULL) {
+ V8::FatalProcessOutOfMemory("HashMap::Initialize");
+ return;
+ }
capacity_ = capacity;
Clear();
}
diff --git a/V8Binding/v8/src/heap-inl.h b/V8Binding/v8/src/heap-inl.h
index 36c6f4b..d27f14f 100644
--- a/V8Binding/v8/src/heap-inl.h
+++ b/V8Binding/v8/src/heap-inl.h
@@ -228,6 +228,31 @@ void Heap::ScavengeObject(HeapObject** p, HeapObject* object) {
}
+int Heap::AdjustAmountOfExternalAllocatedMemory(int change_in_bytes) {
+ ASSERT(HasBeenSetup());
+ int amount = amount_of_external_allocated_memory_ + change_in_bytes;
+ if (change_in_bytes >= 0) {
+ // Avoid overflow.
+ if (amount > amount_of_external_allocated_memory_) {
+ amount_of_external_allocated_memory_ = amount;
+ }
+ int amount_since_last_global_gc =
+ amount_of_external_allocated_memory_ -
+ amount_of_external_allocated_memory_at_last_global_gc_;
+ if (amount_since_last_global_gc > external_allocation_limit_) {
+ CollectAllGarbage();
+ }
+ } else {
+ // Avoid underflow.
+ if (amount >= 0) {
+ amount_of_external_allocated_memory_ = amount;
+ }
+ }
+ ASSERT(amount_of_external_allocated_memory_ >= 0);
+ return amount_of_external_allocated_memory_;
+}
+
+
void Heap::SetLastScriptId(Object* last_script_id) {
roots_[kLastScriptIdRootIndex] = last_script_id;
}
diff --git a/V8Binding/v8/src/heap.cc b/V8Binding/v8/src/heap.cc
index 64059b1..213eec5 100644
--- a/V8Binding/v8/src/heap.cc
+++ b/V8Binding/v8/src/heap.cc
@@ -56,13 +56,8 @@ MapSpace* Heap::map_space_ = NULL;
CellSpace* Heap::cell_space_ = NULL;
LargeObjectSpace* Heap::lo_space_ = NULL;
-#if defined(ANDROID)
-static const int kMinimumPromotionLimit = 1*MB;
-static const int kMinimumAllocationLimit = 2*MB;
-#else
static const int kMinimumPromotionLimit = 2*MB;
static const int kMinimumAllocationLimit = 8*MB;
-#endif
int Heap::old_gen_promotion_limit_ = kMinimumPromotionLimit;
int Heap::old_gen_allocation_limit_ = kMinimumAllocationLimit;
@@ -90,8 +85,8 @@ GCCallback Heap::global_gc_epilogue_callback_ = NULL;
// Variables set based on semispace_size_ and old_generation_size_ in
// ConfigureHeap.
int Heap::young_generation_size_ = 0; // Will be 2 * semispace_size_.
-
int Heap::survived_since_last_expansion_ = 0;
+int Heap::external_allocation_limit_ = 0;
Heap::HeapState Heap::gc_state_ = NOT_IN_GC;
@@ -1192,7 +1187,7 @@ bool Heap::CreateInitialMaps() {
set_undetectable_long_ascii_string_map(Map::cast(obj));
Map::cast(obj)->set_is_undetectable();
- obj = AllocateMap(BYTE_ARRAY_TYPE, Array::kAlignedSize);
+ obj = AllocateMap(BYTE_ARRAY_TYPE, ByteArray::kAlignedSize);
if (obj->IsFailure()) return false;
set_byte_array_map(Map::cast(obj));
@@ -2993,6 +2988,7 @@ bool Heap::ConfigureHeap(int semispace_size, int old_gen_size) {
semispace_size_ = RoundUpToPowerOf2(semispace_size_);
initial_semispace_size_ = Min(initial_semispace_size_, semispace_size_);
young_generation_size_ = 2 * semispace_size_;
+ external_allocation_limit_ = 10 * semispace_size_;
// The old generation is paged.
old_generation_size_ = RoundUp(old_generation_size_, Page::kPageSize);
@@ -3411,6 +3407,8 @@ void HeapProfiler::CollectStats(HeapObject* obj, HistogramInfo* info) {
#ifdef ENABLE_LOGGING_AND_PROFILING
void HeapProfiler::WriteSample() {
LOG(HeapSampleBeginEvent("Heap", "allocated"));
+ LOG(HeapSampleStats(
+ "Heap", "allocated", Heap::Capacity(), Heap::SizeOfObjects()));
HistogramInfo info[LAST_TYPE+1];
#define DEF_TYPE_NAME(name) info[name].set_name(#name);
diff --git a/V8Binding/v8/src/heap.h b/V8Binding/v8/src/heap.h
index 55a66bc..4e2c64c 100644
--- a/V8Binding/v8/src/heap.h
+++ b/V8Binding/v8/src/heap.h
@@ -746,7 +746,7 @@ class Heap : public AllStatic {
static Object* CreateSymbol(String* str);
// Write barrier support for address[offset] = o.
- inline static void RecordWrite(Address address, int offset);
+ static inline void RecordWrite(Address address, int offset);
// Given an address occupied by a live code object, return that object.
static Object* FindCodeObject(Address a);
@@ -802,22 +802,7 @@ class Heap : public AllStatic {
// Adjusts the amount of registered external memory.
// Returns the adjusted value.
- static int AdjustAmountOfExternalAllocatedMemory(int change_in_bytes) {
- int amount = amount_of_external_allocated_memory_ + change_in_bytes;
- if (change_in_bytes >= 0) {
- // Avoid overflow.
- if (amount > amount_of_external_allocated_memory_) {
- amount_of_external_allocated_memory_ = amount;
- }
- } else {
- // Avoid underflow.
- if (amount >= 0) {
- amount_of_external_allocated_memory_ = amount;
- }
- }
- ASSERT(amount_of_external_allocated_memory_ >= 0);
- return amount_of_external_allocated_memory_;
- }
+ static inline int AdjustAmountOfExternalAllocatedMemory(int change_in_bytes);
// Allocate unitialized fixed array (pretenure == NON_TENURE).
static Object* AllocateRawFixedArray(int length);
@@ -901,6 +886,10 @@ class Heap : public AllStatic {
// every allocation in large object space.
static int old_gen_allocation_limit_;
+ // Limit on the amount of externally allocated memory allowed
+ // between global GCs. If reached a global GC is forced.
+ static int external_allocation_limit_;
+
// The amount of external memory registered through the API kept alive
// by global handles
static int amount_of_external_allocated_memory_;
@@ -1230,7 +1219,7 @@ class KeyedLookupCache {
// Clear the cache.
static void Clear();
private:
- inline static int Hash(Map* map, String* name);
+ static inline int Hash(Map* map, String* name);
static const int kLength = 64;
struct Key {
Map* map;
diff --git a/V8Binding/v8/src/ia32/codegen-ia32.cc b/V8Binding/v8/src/ia32/codegen-ia32.cc
index 6d1dc2d..457b22f 100644
--- a/V8Binding/v8/src/ia32/codegen-ia32.cc
+++ b/V8Binding/v8/src/ia32/codegen-ia32.cc
@@ -3857,7 +3857,7 @@ Result CodeGenerator::LoadFromGlobalSlotCheckExtensions(
s = s->outer_scope();
}
- if (s->is_eval_scope()) {
+ if (s != NULL && s->is_eval_scope()) {
// Loop up the context chain. There is no frame effect so it is
// safe to use raw labels here.
Label next, fast;
@@ -4351,7 +4351,7 @@ void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
FieldOperand(elements.reg(), JSObject::kElementsOffset));
// Write to the indexed properties array.
- int offset = i * kPointerSize + Array::kHeaderSize;
+ int offset = i * kPointerSize + FixedArray::kHeaderSize;
__ mov(FieldOperand(elements.reg(), offset), prop_value.reg());
// Update the write barrier for the array address.
@@ -5388,12 +5388,6 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
} else {
Load(node->expression());
switch (op) {
- case Token::NOT:
- case Token::DELETE:
- case Token::TYPEOF:
- UNREACHABLE(); // handled above
- break;
-
case Token::SUB: {
bool overwrite =
(node->AsBinaryOperation() != NULL &&
@@ -5448,6 +5442,8 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
}
default:
+ // NOT, DELETE, TYPEOF, and VOID are handled outside the
+ // switch.
UNREACHABLE();
}
}
@@ -6309,7 +6305,7 @@ void Reference::GetValue(TypeofState typeof_state) {
__ mov(index.reg(), key.reg());
__ sar(index.reg(), kSmiTagSize);
__ cmp(index.reg(),
- FieldOperand(elements.reg(), Array::kLengthOffset));
+ FieldOperand(elements.reg(), FixedArray::kLengthOffset));
deferred->Branch(above_equal);
// Load and check that the result is not the hole. We could
@@ -6323,7 +6319,7 @@ void Reference::GetValue(TypeofState typeof_state) {
__ mov(value.reg(), Operand(elements.reg(),
index.reg(),
times_4,
- Array::kHeaderSize - kHeapObjectTag));
+ FixedArray::kHeaderSize - kHeapObjectTag));
elements.Unuse();
index.Unuse();
__ cmp(Operand(value.reg()), Immediate(Factory::the_hole_value()));
@@ -6495,7 +6491,7 @@ void Reference::SetValue(InitState init_state) {
__ mov(Operand(tmp.reg(),
key.reg(),
times_2,
- Array::kHeaderSize - kHeapObjectTag),
+ FixedArray::kHeaderSize - kHeapObjectTag),
value.reg());
__ IncrementCounter(&Counters::keyed_store_inline, 1);
diff --git a/V8Binding/v8/src/ia32/ic-ia32.cc b/V8Binding/v8/src/ia32/ic-ia32.cc
index 90e0fd1..d64dee1 100644
--- a/V8Binding/v8/src/ia32/ic-ia32.cc
+++ b/V8Binding/v8/src/ia32/ic-ia32.cc
@@ -43,6 +43,10 @@ namespace internal {
// Helper function used to load a property from a dictionary backing storage.
+// This function may return false negatives, so miss_label
+// must always call a backup property load that is complete.
+// This function is safe to call if the receiver has fast properties,
+// or if name is not a symbol, and will jump to the miss_label in that case.
static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
Register r0, Register r1, Register r2,
Register name) {
@@ -56,7 +60,7 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
//
// r2 - used to hold the capacity of the property dictionary.
//
- // name - holds the name of the property and is unchanges.
+ // name - holds the name of the property and is unchanged.
Label done;
@@ -89,7 +93,8 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
// Compute the capacity mask.
const int kCapacityOffset =
- Array::kHeaderSize + StringDictionary::kCapacityIndex * kPointerSize;
+ StringDictionary::kHeaderSize +
+ StringDictionary::kCapacityIndex * kPointerSize;
__ mov(r2, FieldOperand(r0, kCapacityOffset));
__ shr(r2, kSmiTagSize); // convert smi to int
__ dec(r2);
@@ -99,7 +104,8 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
// cover ~93% of loads from dictionaries.
static const int kProbes = 4;
const int kElementsStartOffset =
- Array::kHeaderSize + StringDictionary::kElementsStartIndex * kPointerSize;
+ StringDictionary::kHeaderSize +
+ StringDictionary::kElementsStartIndex * kPointerSize;
for (int i = 0; i < kProbes; i++) {
// Compute the masked index: (hash + i + i * i) & mask.
__ mov(r1, FieldOperand(name, String::kLengthOffset));
@@ -153,6 +159,9 @@ static void GenerateCheckNonObjectOrLoaded(MacroAssembler* masm, Label* miss,
}
+// The offset from the inlined patch site to the start of the
+// inlined load instruction. It is 7 bytes (test eax, imm) plus
+// 6 bytes (jne slow_label).
const int LoadIC::kOffsetToLoadInstruction = 13;
@@ -263,21 +272,28 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
Immediate(Factory::hash_table_map()));
__ j(equal, &slow, not_taken);
// Check that the key (index) is within bounds.
- __ cmp(eax, FieldOperand(ecx, Array::kLengthOffset));
+ __ cmp(eax, FieldOperand(ecx, FixedArray::kLengthOffset));
__ j(below, &fast, taken);
// Slow case: Load name and receiver from stack and jump to runtime.
__ bind(&slow);
__ IncrementCounter(&Counters::keyed_load_generic_slow, 1);
KeyedLoadIC::Generate(masm, ExternalReference(Runtime::kKeyedGetProperty));
- // Check if the key is a symbol that is not an array index.
+
__ bind(&check_string);
+ // The key is not a smi.
+ // Is it a string?
+ __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
+ __ j(above_equal, &slow);
+ // Is the string an array index, with cached numeric value?
__ mov(ebx, FieldOperand(eax, String::kLengthOffset));
__ test(ebx, Immediate(String::kIsArrayIndexMask));
__ j(not_zero, &index_string, not_taken);
- __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
- __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
+
+ // If the string is a symbol, do a quick inline probe of the receiver's
+ // dictionary, if it exists.
+ __ movzx_b(ebx, FieldOperand(edx, Map::kInstanceTypeOffset));
__ test(ebx, Immediate(kIsSymbolMask));
- __ j(not_zero, &slow, not_taken);
+ __ j(zero, &slow, not_taken);
// Probe the dictionary leaving result in ecx.
GenerateDictionaryLoad(masm, &slow, ebx, ecx, edx, eax);
GenerateCheckNonObjectOrLoaded(masm, &slow, ecx, edx);
@@ -301,7 +317,8 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
__ jmp(&index_int);
// Fast case: Do the load.
__ bind(&fast);
- __ mov(eax, Operand(ecx, eax, times_4, Array::kHeaderSize - kHeapObjectTag));
+ __ mov(eax,
+ Operand(ecx, eax, times_4, FixedArray::kHeaderSize - kHeapObjectTag));
__ cmp(Operand(eax), Immediate(Factory::the_hole_value()));
// In case the loaded value is the_hole we have to consult GetProperty
// to ensure the prototype chain is searched.
@@ -419,7 +436,8 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
// eax: value
// ecx: FixedArray
// ebx: index (as a smi)
- __ mov(Operand(ecx, ebx, times_2, Array::kHeaderSize - kHeapObjectTag), eax);
+ __ mov(Operand(ecx, ebx, times_2, FixedArray::kHeaderSize - kHeapObjectTag),
+ eax);
// Update write barrier for the elements array address.
__ mov(edx, Operand(eax));
__ RecordWrite(ecx, 0, edx, ebx);
diff --git a/V8Binding/v8/src/ia32/macro-assembler-ia32.cc b/V8Binding/v8/src/ia32/macro-assembler-ia32.cc
index 479b8ca..fae1525 100644
--- a/V8Binding/v8/src/ia32/macro-assembler-ia32.cc
+++ b/V8Binding/v8/src/ia32/macro-assembler-ia32.cc
@@ -79,7 +79,7 @@ static void RecordWriteHelper(MacroAssembler* masm,
// Add the page header, array header, and array body size to the page
// address.
masm->add(Operand(object), Immediate(Page::kObjectStartOffset
- + Array::kHeaderSize));
+ + FixedArray::kHeaderSize));
masm->add(object, Operand(scratch));
@@ -199,9 +199,10 @@ void MacroAssembler::RecordWrite(Register object, int offset,
lea(dst, Operand(object, offset));
} else {
// array access: calculate the destination address in the same manner as
- // KeyedStoreIC::GenerateGeneric
- lea(dst,
- Operand(object, dst, times_2, Array::kHeaderSize - kHeapObjectTag));
+ // KeyedStoreIC::GenerateGeneric. Multiply a smi by 2 to get an offset
+ // into an array of words.
+ lea(dst, Operand(object, dst, times_2,
+ FixedArray::kHeaderSize - kHeapObjectTag));
}
// If we are already generating a shared stub, not inlining the
// record write code isn't going to save us any memory.
diff --git a/V8Binding/v8/src/ia32/regexp-macro-assembler-ia32.cc b/V8Binding/v8/src/ia32/regexp-macro-assembler-ia32.cc
index 04a5390..c5d7c05 100644
--- a/V8Binding/v8/src/ia32/regexp-macro-assembler-ia32.cc
+++ b/V8Binding/v8/src/ia32/regexp-macro-assembler-ia32.cc
@@ -1073,10 +1073,12 @@ int RegExpMacroAssemblerIA32::CaseInsensitiveCompareUC16(Address byte_offset1,
unibrow::uchar c1 = substring1[i];
unibrow::uchar c2 = substring2[i];
if (c1 != c2) {
- canonicalize.get(c1, '\0', &c1);
- if (c1 != c2) {
- canonicalize.get(c2, '\0', &c2);
- if (c1 != c2) {
+ unibrow::uchar s1[1] = { c1 };
+ canonicalize.get(c1, '\0', s1);
+ if (s1[0] != c2) {
+ unibrow::uchar s2[1] = { c2 };
+ canonicalize.get(c2, '\0', s2);
+ if (s1[0] != s2[0]) {
return 0;
}
}
diff --git a/V8Binding/v8/src/ia32/register-allocator-ia32-inl.h b/V8Binding/v8/src/ia32/register-allocator-ia32-inl.h
index ddee472..99ae6eb 100644
--- a/V8Binding/v8/src/ia32/register-allocator-ia32-inl.h
+++ b/V8Binding/v8/src/ia32/register-allocator-ia32-inl.h
@@ -49,7 +49,7 @@ bool RegisterAllocator::IsReserved(Register reg) {
int RegisterAllocator::ToNumber(Register reg) {
ASSERT(reg.is_valid() && !IsReserved(reg));
- static int numbers[] = {
+ const int kNumbers[] = {
0, // eax
2, // ecx
3, // edx
@@ -59,14 +59,14 @@ int RegisterAllocator::ToNumber(Register reg) {
-1, // esi
4 // edi
};
- return numbers[reg.code()];
+ return kNumbers[reg.code()];
}
Register RegisterAllocator::ToRegister(int num) {
ASSERT(num >= 0 && num < kNumRegisters);
- static Register registers[] = { eax, ebx, ecx, edx, edi };
- return registers[num];
+ const Register kRegisters[] = { eax, ebx, ecx, edx, edi };
+ return kRegisters[num];
}
diff --git a/V8Binding/v8/src/ia32/stub-cache-ia32.cc b/V8Binding/v8/src/ia32/stub-cache-ia32.cc
index 0a887d5..e47ad1c 100644
--- a/V8Binding/v8/src/ia32/stub-cache-ia32.cc
+++ b/V8Binding/v8/src/ia32/stub-cache-ia32.cc
@@ -266,15 +266,13 @@ void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
__ mov(dst, FieldOperand(src, offset));
} else {
// Calculate the offset into the properties array.
- int offset = index * kPointerSize + Array::kHeaderSize;
+ int offset = index * kPointerSize + FixedArray::kHeaderSize;
__ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
__ mov(dst, FieldOperand(dst, offset));
}
}
-
-
void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
Code* code = NULL;
@@ -349,7 +347,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
__ RecordWrite(receiver_reg, offset, name_reg, scratch);
} else {
// Write to the properties array.
- int offset = index * kPointerSize + Array::kHeaderSize;
+ int offset = index * kPointerSize + FixedArray::kHeaderSize;
// Get the properties array (optimistically).
__ mov(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
__ mov(FieldOperand(scratch, offset), eax);
diff --git a/V8Binding/v8/src/ic.cc b/V8Binding/v8/src/ic.cc
index 7e82295..090d7a3 100644
--- a/V8Binding/v8/src/ic.cc
+++ b/V8Binding/v8/src/ic.cc
@@ -273,28 +273,39 @@ static bool HasInterceptorGetter(JSObject* object) {
static void LookupForRead(Object* object,
String* name,
LookupResult* lookup) {
- object->Lookup(name, lookup);
- if (lookup->IsNotFound() || lookup->type() != INTERCEPTOR) {
- return;
- }
+ AssertNoAllocation no_gc; // pointers must stay valid
+
+ // Skip all the objects with named interceptors, but
+ // without actual getter.
+ while (true) {
+ object->Lookup(name, lookup);
+ // Besides normal conditions (property not found or it's not
+ // an interceptor), bail out of lookup is not cacheable: we won't
+ // be able to IC it anyway and regular lookup should work fine.
+ if (lookup->IsNotFound() || lookup->type() != INTERCEPTOR ||
+ !lookup->IsCacheable()) {
+ return;
+ }
- JSObject* holder = lookup->holder();
- if (HasInterceptorGetter(holder)) {
- return;
- }
+ JSObject* holder = lookup->holder();
+ if (HasInterceptorGetter(holder)) {
+ return;
+ }
- // There is no getter, just skip it and lookup down the proto chain
- holder->LocalLookupRealNamedProperty(name, lookup);
- if (lookup->IsValid()) {
- return;
- }
+ holder->LocalLookupRealNamedProperty(name, lookup);
+ if (lookup->IsValid()) {
+ ASSERT(lookup->type() != INTERCEPTOR);
+ return;
+ }
- Object* proto = holder->GetPrototype();
- if (proto == Heap::null_value()) {
- return;
- }
+ Object* proto = holder->GetPrototype();
+ if (proto->IsNull()) {
+ lookup->NotFound();
+ return;
+ }
- LookupForRead(proto, name, lookup);
+ object = proto;
+ }
}
@@ -726,7 +737,9 @@ Object* KeyedLoadIC::Load(State state,
return TypeError("non_object_property_load", object, name);
}
- if (FLAG_use_ic) {
+ // TODO(X64): Enable specialized stubs for length and prototype lookup.
+#ifndef V8_TARGET_ARCH_X64
+ if (false && FLAG_use_ic) {
// Use specialized code for getting the length of strings.
if (object->IsString() && name->Equals(Heap::length_symbol())) {
Handle<String> string = Handle<String>::cast(object);
@@ -736,7 +749,7 @@ Object* KeyedLoadIC::Load(State state,
set_target(Code::cast(code));
#ifdef DEBUG
TraceIC("KeyedLoadIC", name, state, target());
-#endif
+#endif // DEBUG
return Smi::FromInt(string->length());
}
@@ -748,7 +761,7 @@ Object* KeyedLoadIC::Load(State state,
set_target(Code::cast(code));
#ifdef DEBUG
TraceIC("KeyedLoadIC", name, state, target());
-#endif
+#endif // DEBUG
return JSArray::cast(*object)->length();
}
@@ -761,10 +774,11 @@ Object* KeyedLoadIC::Load(State state,
set_target(Code::cast(code));
#ifdef DEBUG
TraceIC("KeyedLoadIC", name, state, target());
-#endif
+#endif // DEBUG
return Accessors::FunctionGetPrototype(*object, 0);
}
}
+#endif // !V8_TARGET_ARCH_X64
// Check if the name is trivially convertible to an index and get
// the element or char if so.
@@ -787,10 +801,13 @@ Object* KeyedLoadIC::Load(State state,
}
}
+ // TODO(X64): Enable inline caching for load.
+#ifndef V8_TARGET_ARCH_X64
// Update the inline cache.
if (FLAG_use_ic && lookup.IsLoaded()) {
UpdateCaches(&lookup, state, object, name);
}
+#endif
PropertyAttributes attr;
if (lookup.IsValid() && lookup.type() == INTERCEPTOR) {
@@ -961,6 +978,10 @@ Object* StoreIC::Store(State state,
return *value;
}
+ // TODO(X64): Enable inline cache for StoreIC.
+#ifdef V8_TARGET_ARCH_X64
+ USE(&LookupForWrite); // The compiler complains otherwise.
+#else
// Lookup the property locally in the receiver.
if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) {
LookupResult lookup;
@@ -968,6 +989,7 @@ Object* StoreIC::Store(State state,
UpdateCaches(&lookup, state, receiver, name, value);
}
}
+#endif
// Set the property.
return receiver->SetProperty(*name, *value, NONE);
@@ -1086,10 +1108,13 @@ Object* KeyedStoreIC::Store(State state,
LookupResult lookup;
receiver->LocalLookup(*name, &lookup);
+ // TODO(X64): Enable inline cache for KeyedStoreIC.
+#ifndef V8_TARGET_ARCH_X64
// Update inline cache and stub cache.
if (FLAG_use_ic && lookup.IsLoaded()) {
UpdateCaches(&lookup, state, receiver, name, value);
}
+#endif
// Set the property.
return receiver->SetProperty(*name, *value, NONE);
@@ -1221,11 +1246,6 @@ void CallIC::GenerateInitialize(MacroAssembler* masm, int argc) {
}
-void CallIC::GeneratePreMonomorphic(MacroAssembler* masm, int argc) {
- Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
-}
-
-
void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
}
diff --git a/V8Binding/v8/src/ic.h b/V8Binding/v8/src/ic.h
index 7d03377..593519b 100644
--- a/V8Binding/v8/src/ic.h
+++ b/V8Binding/v8/src/ic.h
@@ -49,7 +49,8 @@ namespace internal {
ICU(StoreInterceptorProperty)
//
-// IC is the base class for LoadIC, StoreIC and CallIC.
+// IC is the base class for LoadIC, StoreIC, CallIC, KeyedLoadIC,
+// and KeyedStoreIC.
//
class IC {
public:
@@ -173,7 +174,6 @@ class CallIC: public IC {
// Code generator routines.
static void GenerateInitialize(MacroAssembler* masm, int argc);
- static void GeneratePreMonomorphic(MacroAssembler* masm, int argc);
static void GenerateMiss(MacroAssembler* masm, int argc);
static void GenerateMegamorphic(MacroAssembler* masm, int argc);
static void GenerateNormal(MacroAssembler* masm, int argc);
@@ -219,8 +219,8 @@ class LoadIC: public IC {
static void GenerateFunctionPrototype(MacroAssembler* masm);
// The offset from the inlined patch site to the start of the
- // inlined load instruction. It is 7 bytes (test eax, imm) plus
- // 6 bytes (jne slow_label).
+ // inlined load instruction. It is architecture-dependent, and not
+ // used on ARM.
static const int kOffsetToLoadInstruction;
private:
diff --git a/V8Binding/v8/src/interpreter-irregexp.cc b/V8Binding/v8/src/interpreter-irregexp.cc
index 0a8ae8c..ae914d3 100644
--- a/V8Binding/v8/src/interpreter-irregexp.cc
+++ b/V8Binding/v8/src/interpreter-irregexp.cc
@@ -51,9 +51,11 @@ static bool BackRefMatchesNoCase(int from,
unibrow::uchar old_char = subject[from++];
unibrow::uchar new_char = subject[current++];
if (old_char == new_char) continue;
- interp_canonicalize.get(old_char, '\0', &old_char);
- interp_canonicalize.get(new_char, '\0', &new_char);
- if (old_char != new_char) {
+ unibrow::uchar old_string[1] = { old_char };
+ unibrow::uchar new_string[1] = { new_char };
+ interp_canonicalize.get(old_char, '\0', old_string);
+ interp_canonicalize.get(new_char, '\0', new_string);
+ if (old_string[0] != new_string[0]) {
return false;
}
}
diff --git a/V8Binding/v8/src/log.cc b/V8Binding/v8/src/log.cc
index 2ca89dd..33cf8e2 100644
--- a/V8Binding/v8/src/log.cc
+++ b/V8Binding/v8/src/log.cc
@@ -843,7 +843,22 @@ void Logger::HeapSampleBeginEvent(const char* space, const char* kind) {
#ifdef ENABLE_LOGGING_AND_PROFILING
if (!Log::IsEnabled() || !FLAG_log_gc) return;
LogMessageBuilder msg;
- msg.Append("heap-sample-begin,\"%s\",\"%s\"\n", space, kind);
+ // Using non-relative system time in order to be able to synchronize with
+ // external memory profiling events (e.g. DOM memory size).
+ msg.Append("heap-sample-begin,\"%s\",\"%s\",%.0f\n",
+ space, kind, OS::TimeCurrentMillis());
+ msg.WriteToLogFile();
+#endif
+}
+
+
+void Logger::HeapSampleStats(const char* space, const char* kind,
+ int capacity, int used) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ if (!Log::IsEnabled() || !FLAG_log_gc) return;
+ LogMessageBuilder msg;
+ msg.Append("heap-sample-stats,\"%s\",\"%s\",%d,%d\n",
+ space, kind, capacity, used);
msg.WriteToLogFile();
#endif
}
diff --git a/V8Binding/v8/src/log.h b/V8Binding/v8/src/log.h
index f68234f..95c9cde 100644
--- a/V8Binding/v8/src/log.h
+++ b/V8Binding/v8/src/log.h
@@ -219,6 +219,8 @@ class Logger {
static void HeapSampleBeginEvent(const char* space, const char* kind);
static void HeapSampleEndEvent(const char* space, const char* kind);
static void HeapSampleItemEvent(const char* type, int number, int bytes);
+ static void HeapSampleStats(const char* space, const char* kind,
+ int capacity, int used);
static void SharedLibraryEvent(const char* library_path,
uintptr_t start,
diff --git a/V8Binding/v8/src/objects-inl.h b/V8Binding/v8/src/objects-inl.h
index 37c9b8b..7abc7c3 100644
--- a/V8Binding/v8/src/objects-inl.h
+++ b/V8Binding/v8/src/objects-inl.h
@@ -1075,7 +1075,12 @@ void JSGlobalPropertyCell::set_value(Object* val, WriteBarrierMode ignored) {
int JSObject::GetHeaderSize() {
- switch (map()->instance_type()) {
+ InstanceType type = map()->instance_type();
+ // Check for the most common kind of JavaScript object before
+ // falling into the generic switch. This speeds up the internal
+ // field operations considerably on average.
+ if (type == JS_OBJECT_TYPE) return JSObject::kHeaderSize;
+ switch (type) {
case JS_GLOBAL_PROXY_TYPE:
return JSGlobalProxy::kSize;
case JS_GLOBAL_OBJECT_TYPE:
@@ -1090,7 +1095,6 @@ int JSObject::GetHeaderSize() {
return JSValue::kSize;
case JS_REGEXP_TYPE:
return JSValue::kSize;
- case JS_OBJECT_TYPE:
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
return JSObject::kHeaderSize;
default:
diff --git a/V8Binding/v8/src/objects.cc b/V8Binding/v8/src/objects.cc
index a9004c9..72412c1 100644
--- a/V8Binding/v8/src/objects.cc
+++ b/V8Binding/v8/src/objects.cc
@@ -216,6 +216,12 @@ Object* Object::GetPropertyWithDefinedGetter(Object* receiver,
HandleScope scope;
Handle<JSFunction> fun(JSFunction::cast(getter));
Handle<Object> self(receiver);
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ // Handle stepping into a getter if step into is active.
+ if (Debug::StepInActive()) {
+ Debug::HandleStepIn(fun, Handle<Object>::null(), 0, false);
+ }
+#endif
bool has_pending_exception;
Handle<Object> result =
Execution::Call(fun, self, 0, NULL, &has_pending_exception);
@@ -1624,6 +1630,12 @@ Object* JSObject::SetPropertyWithDefinedSetter(JSFunction* setter,
Handle<Object> value_handle(value);
Handle<JSFunction> fun(JSFunction::cast(setter));
Handle<JSObject> self(this);
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ // Handle stepping into a setter if step into is active.
+ if (Debug::StepInActive()) {
+ Debug::HandleStepIn(fun, Handle<Object>::null(), 0, false);
+ }
+#endif
bool has_pending_exception;
Object** argv[] = { value_handle.location() };
Execution::Call(fun, self, 1, argv, &has_pending_exception);
diff --git a/V8Binding/v8/src/objects.h b/V8Binding/v8/src/objects.h
index 5c76e4a..5e5eb6b 100644
--- a/V8Binding/v8/src/objects.h
+++ b/V8Binding/v8/src/objects.h
@@ -1718,6 +1718,10 @@ class Array: public HeapObject {
// Layout descriptor.
static const int kLengthOffset = HeapObject::kHeaderSize;
+
+ protected:
+ // No code should use the Array class directly, only its subclasses.
+ // Use the kHeaderSize of the appropriate subclass, which may be aligned.
static const int kHeaderSize = kLengthOffset + kIntSize;
static const int kAlignedSize = POINTER_SIZE_ALIGN(kHeaderSize);
@@ -2427,6 +2431,10 @@ class ByteArray: public Array {
void ByteArrayVerify();
#endif
+ // ByteArray headers are not quadword aligned.
+ static const int kHeaderSize = Array::kHeaderSize;
+ static const int kAlignedSize = Array::kAlignedSize;
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ByteArray);
};
diff --git a/V8Binding/v8/src/parser.cc b/V8Binding/v8/src/parser.cc
index 89d6d5b..da2b286 100644
--- a/V8Binding/v8/src/parser.cc
+++ b/V8Binding/v8/src/parser.cc
@@ -834,12 +834,7 @@ class AstBuildingParserFactory : public ParserFactory {
return new CallEval(expression, arguments, pos);
}
- virtual Statement* EmptyStatement() {
- // Use a statically allocated empty statement singleton to avoid
- // allocating lots and lots of empty statements.
- static v8::internal::EmptyStatement empty;
- return &empty;
- }
+ virtual Statement* EmptyStatement();
};
@@ -1032,6 +1027,14 @@ Scope* AstBuildingParserFactory::NewScope(Scope* parent, Scope::Type type,
}
+Statement* AstBuildingParserFactory::EmptyStatement() {
+ // Use a statically allocated empty statement singleton to avoid
+ // allocating lots and lots of empty statements.
+ static v8::internal::EmptyStatement empty;
+ return &empty;
+}
+
+
Scope* ParserFactory::NewScope(Scope* parent, Scope::Type type,
bool inside_with) {
ASSERT(parent != NULL);
@@ -2367,7 +2370,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
result = NEW(TryFinally(try_block, finally_block));
// Add the jump targets of the try block and the catch block.
for (int i = 0; i < collector.targets()->length(); i++) {
- catch_collector.targets()->Add(collector.targets()->at(i));
+ catch_collector.AddTarget(collector.targets()->at(i));
}
result->set_escaping_targets(catch_collector.targets());
}
@@ -3928,7 +3931,7 @@ RegExpTree* RegExpParser::ParseDisjunction() {
case '*':
case '+':
case '?':
- ReportError(CStrVector("Nothing to repeat") CHECK_FAILED);
+ return ReportError(CStrVector("Nothing to repeat"));
case '^': {
Advance();
if (multiline_) {
@@ -4003,7 +4006,7 @@ RegExpTree* RegExpParser::ParseDisjunction() {
case '\\':
switch (Next()) {
case kEndMarker:
- ReportError(CStrVector("\\ at end of pattern") CHECK_FAILED);
+ return ReportError(CStrVector("\\ at end of pattern"));
case 'b':
Advance(2);
builder->AddAssertion(
@@ -4490,7 +4493,7 @@ CharacterRange RegExpParser::ParseClassAtom(uc16* char_class) {
return CharacterRange::Singleton(0); // Return dummy value.
}
case kEndMarker:
- ReportError(CStrVector("\\ at end of pattern") CHECK_FAILED);
+ return ReportError(CStrVector("\\ at end of pattern"));
default:
uc32 c = ParseClassCharacterEscape(CHECK_FAILED);
return CharacterRange::Singleton(c);
diff --git a/V8Binding/v8/src/platform-macos.cc b/V8Binding/v8/src/platform-macos.cc
index 880931e..b5a57e1 100644
--- a/V8Binding/v8/src/platform-macos.cc
+++ b/V8Binding/v8/src/platform-macos.cc
@@ -28,10 +28,11 @@
// Platform specific code for MacOS goes here. For the POSIX comaptible parts
// the implementation is in platform-posix.cc.
-#include <ucontext.h>
#include <unistd.h>
#include <sys/mman.h>
#include <mach/mach_init.h>
+#include <mach-o/dyld.h>
+#include <mach-o/getsect.h>
#include <AvailabilityMacros.h>
@@ -205,7 +206,19 @@ PosixMemoryMappedFile::~PosixMemoryMappedFile() {
void OS::LogSharedLibraryAddresses() {
- // TODO(1233579): Implement.
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ unsigned int images_count = _dyld_image_count();
+ for (unsigned int i = 0; i < images_count; ++i) {
+ const mach_header* header = _dyld_get_image_header(i);
+ if (header == NULL) continue;
+ unsigned int size;
+ char* code_ptr = getsectdatafromheader(header, SEG_TEXT, SECT_TEXT, &size);
+ if (code_ptr == NULL) continue;
+ const uintptr_t slide = _dyld_get_image_vmaddr_slide(i);
+ const uintptr_t start = reinterpret_cast<uintptr_t>(code_ptr) + slide;
+ LOG(SharedLibraryEvent(_dyld_get_image_name(i), start, start + size));
+ }
+#endif // ENABLE_LOGGING_AND_PROFILING
}
diff --git a/V8Binding/v8/src/register-allocator.cc b/V8Binding/v8/src/register-allocator.cc
index d1b08bb..d55f949 100644
--- a/V8Binding/v8/src/register-allocator.cc
+++ b/V8Binding/v8/src/register-allocator.cc
@@ -44,6 +44,12 @@ Result::Result(Register reg) {
}
+Result::ZoneObjectList* Result::ConstantList() {
+ static ZoneObjectList list(10);
+ return &list;
+}
+
+
// -------------------------------------------------------------------------
// RegisterAllocator implementation.
diff --git a/V8Binding/v8/src/register-allocator.h b/V8Binding/v8/src/register-allocator.h
index f7167d9..1765633 100644
--- a/V8Binding/v8/src/register-allocator.h
+++ b/V8Binding/v8/src/register-allocator.h
@@ -92,10 +92,7 @@ class Result BASE_EMBEDDED {
// of handles to the actual constants.
typedef ZoneList<Handle<Object> > ZoneObjectList;
- static ZoneObjectList* ConstantList() {
- static ZoneObjectList list(10);
- return &list;
- }
+ static ZoneObjectList* ConstantList();
// Clear the constants indirection table.
static void ClearConstantList() {
diff --git a/V8Binding/v8/src/rewriter.cc b/V8Binding/v8/src/rewriter.cc
index 4d1fbd9..8a7267a 100644
--- a/V8Binding/v8/src/rewriter.cc
+++ b/V8Binding/v8/src/rewriter.cc
@@ -38,8 +38,9 @@ namespace internal {
class AstOptimizer: public AstVisitor {
public:
- explicit AstOptimizer() {}
- explicit AstOptimizer(Handle<String> enclosing_name) {
+ explicit AstOptimizer() : has_function_literal_(false) {}
+ explicit AstOptimizer(Handle<String> enclosing_name)
+ : has_function_literal_(false) {
func_name_inferrer_.PushEnclosingName(enclosing_name);
}
diff --git a/V8Binding/v8/src/serialize.cc b/V8Binding/v8/src/serialize.cc
index 592cf5a..963138e 100644
--- a/V8Binding/v8/src/serialize.cc
+++ b/V8Binding/v8/src/serialize.cc
@@ -1454,9 +1454,9 @@ void Deserializer::GetLog() {
static void InitPagedSpace(PagedSpace* space,
int capacity,
List<Page*>* page_list) {
- space->EnsureCapacity(capacity);
- // TODO(1240712): PagedSpace::EnsureCapacity can return false due to
- // a failure to allocate from the OS to expand the space.
+ if (!space->EnsureCapacity(capacity)) {
+ V8::FatalProcessOutOfMemory("InitPagedSpace");
+ }
PageIterator it(space, PageIterator::ALL_PAGES);
while (it.has_next()) page_list->Add(it.next());
}
diff --git a/V8Binding/v8/src/spaces.cc b/V8Binding/v8/src/spaces.cc
index 4177856..4f8119f 100644
--- a/V8Binding/v8/src/spaces.cc
+++ b/V8Binding/v8/src/spaces.cc
@@ -133,8 +133,6 @@ PageIterator::PageIterator(PagedSpace* space, Mode mode) : space_(space) {
#endif
stop_page_ = space->last_page_;
break;
- default:
- UNREACHABLE();
}
}
@@ -725,10 +723,10 @@ void PagedSpace::Shrink() {
Page* current_page = top_page->next_page();
// Loop over the pages to the end of the space.
while (current_page->is_valid()) {
- // Advance last_page_to_keep every other step to end up at the midpoint.
#if defined(ANDROID)
- // Free all free chunks.
+ // Free all chunks if possible
#else
+ // Advance last_page_to_keep every other step to end up at the midpoint.
if ((free_pages & 0x1) == 1) {
pages_to_keep++;
last_page_to_keep = last_page_to_keep->next_page();
@@ -751,6 +749,7 @@ void PagedSpace::Shrink() {
last_page_ = p;
p = p->next_page();
}
+
// The difference between free_pages and pages_to_keep is the number of
// pages actually freed.
ASSERT(pages_to_keep <= free_pages);
diff --git a/V8Binding/v8/src/string-stream.cc b/V8Binding/v8/src/string-stream.cc
index 9a137e3..ee343a5 100644
--- a/V8Binding/v8/src/string-stream.cc
+++ b/V8Binding/v8/src/string-stream.cc
@@ -44,12 +44,6 @@ char* HeapStringAllocator::allocate(unsigned bytes) {
}
-NoAllocationStringAllocator::NoAllocationStringAllocator(unsigned bytes) {
- size_ = bytes;
- space_ = NewArray<char>(bytes);
-}
-
-
NoAllocationStringAllocator::NoAllocationStringAllocator(char* memory,
unsigned size) {
size_ = size;
diff --git a/V8Binding/v8/src/string-stream.h b/V8Binding/v8/src/string-stream.h
index 15a72e0..5732944 100644
--- a/V8Binding/v8/src/string-stream.h
+++ b/V8Binding/v8/src/string-stream.h
@@ -57,11 +57,10 @@ class HeapStringAllocator: public StringAllocator {
// Allocator for use when no new c++ heap allocation is allowed.
-// Allocates all space up front and does no allocation while building
-// message.
+// Given a preallocated buffer up front and does no allocation while
+// building message.
class NoAllocationStringAllocator: public StringAllocator {
public:
- explicit NoAllocationStringAllocator(unsigned bytes);
NoAllocationStringAllocator(char* memory, unsigned size);
char* allocate(unsigned bytes) { return space_; }
char* grow(unsigned* bytes);
diff --git a/V8Binding/v8/src/stub-cache.cc b/V8Binding/v8/src/stub-cache.cc
index 7eb8cd3..7ca2677 100644
--- a/V8Binding/v8/src/stub-cache.cc
+++ b/V8Binding/v8/src/stub-cache.cc
@@ -863,6 +863,8 @@ Object* StubCompiler::CompileCallInitialize(Code::Flags flags) {
Object* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
HandleScope scope;
int argc = Code::ExtractArgumentsCountFromFlags(flags);
+ // The code of the PreMonomorphic stub is the same as the code
+ // of the Initialized stub. They just differ on the code object flags.
CallIC::GenerateInitialize(masm(), argc);
Object* result = GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
if (!result->IsFailure()) {
diff --git a/V8Binding/v8/src/stub-cache.h b/V8Binding/v8/src/stub-cache.h
index 8bee370..c6b002b 100644
--- a/V8Binding/v8/src/stub-cache.h
+++ b/V8Binding/v8/src/stub-cache.h
@@ -256,11 +256,14 @@ class StubCache : public AllStatic {
}
// Compute the entry for a given offset in exactly the same way as
- // we done in generated code. This makes it a lot easier to avoid
- // making mistakes in the hashed offset computations.
+ // we do in generated code. We generate an hash code that already
+ // ends in String::kHashShift 0s. Then we shift it so it is a multiple
+ // of sizeof(Entry). This makes it easier to avoid making mistakes
+ // in the hashed offset computations.
static Entry* entry(Entry* table, int offset) {
+ const int shift_amount = kPointerSizeLog2 + 1 - String::kHashShift;
return reinterpret_cast<Entry*>(
- reinterpret_cast<Address>(table) + (offset << 1));
+ reinterpret_cast<Address>(table) + (offset << shift_amount));
}
};
diff --git a/V8Binding/v8/src/x64/assembler-x64.cc b/V8Binding/v8/src/x64/assembler-x64.cc
index c4ee454..e9a6f7f1 100644
--- a/V8Binding/v8/src/x64/assembler-x64.cc
+++ b/V8Binding/v8/src/x64/assembler-x64.cc
@@ -456,13 +456,13 @@ void Assembler::arithmetic_op_32(byte opcode, Register dst, Register src) {
void Assembler::arithmetic_op_32(byte opcode,
- const Operand& dst,
- Register src) {
+ Register reg,
+ const Operand& rm_reg) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
- emit_optional_rex_32(src, dst);
+ emit_optional_rex_32(reg, rm_reg);
emit(opcode);
- emit_operand(src, dst);
+ emit_operand(reg, rm_reg);
}
@@ -2183,48 +2183,3 @@ const int RelocInfo::kApplyMask = 1 << RelocInfo::INTERNAL_REFERENCE;
} } // namespace v8::internal
-
-
-// TODO(x64): Implement and move these to their correct cc-files:
-#include "ast.h"
-#include "bootstrapper.h"
-#include "codegen-inl.h"
-#include "cpu.h"
-#include "debug.h"
-#include "disasm.h"
-#include "disassembler.h"
-#include "frames-inl.h"
-#include "x64/macro-assembler-x64.h"
-#include "x64/regexp-macro-assembler-x64.h"
-#include "ic-inl.h"
-#include "log.h"
-#include "macro-assembler.h"
-#include "parser.h"
-#include "regexp-macro-assembler.h"
-#include "regexp-stack.h"
-#include "register-allocator-inl.h"
-#include "register-allocator.h"
-#include "runtime.h"
-#include "scopes.h"
-#include "serialize.h"
-#include "stub-cache.h"
-#include "unicode.h"
-
-namespace v8 {
-namespace internal {
-
-
-void BreakLocationIterator::ClearDebugBreakAtReturn() {
- UNIMPLEMENTED();
-}
-
-bool BreakLocationIterator::IsDebugBreakAtReturn() {
- UNIMPLEMENTED();
- return false;
-}
-
-void BreakLocationIterator::SetDebugBreakAtReturn() {
- UNIMPLEMENTED();
-}
-
-} } // namespace v8::internal
diff --git a/V8Binding/v8/src/x64/assembler-x64.h b/V8Binding/v8/src/x64/assembler-x64.h
index e895332..1b2a35c 100644
--- a/V8Binding/v8/src/x64/assembler-x64.h
+++ b/V8Binding/v8/src/x64/assembler-x64.h
@@ -521,10 +521,6 @@ class Assembler : public Malloced {
void xchg(Register dst, Register src);
// Arithmetics
- void addq(Register dst, Register src) {
- arithmetic_op(0x03, dst, src);
- }
-
void addl(Register dst, Register src) {
arithmetic_op_32(0x03, dst, src);
}
@@ -533,14 +529,21 @@ class Assembler : public Malloced {
immediate_arithmetic_op_32(0x0, dst, src);
}
+ void addl(Register dst, const Operand& src) {
+ arithmetic_op_32(0x03, dst, src);
+ }
+
void addl(const Operand& dst, Immediate src) {
immediate_arithmetic_op_32(0x0, dst, src);
}
- void addq(Register dst, const Operand& src) {
+ void addq(Register dst, Register src) {
arithmetic_op(0x03, dst, src);
}
+ void addq(Register dst, const Operand& src) {
+ arithmetic_op(0x03, dst, src);
+ }
void addq(const Operand& dst, Register src) {
arithmetic_op(0x01, src, dst);
@@ -567,11 +570,11 @@ class Assembler : public Malloced {
}
void cmpl(Register dst, const Operand& src) {
- arithmetic_op_32(0x3B, src, dst);
+ arithmetic_op_32(0x3B, dst, src);
}
void cmpl(const Operand& dst, Register src) {
- arithmetic_op_32(0x39, dst, src);
+ arithmetic_op_32(0x39, src, dst);
}
void cmpl(Register dst, Immediate src) {
@@ -718,6 +721,10 @@ class Assembler : public Malloced {
shift_32(dst, 0x4);
}
+ void shll(Register dst, Immediate shift_amount) {
+ shift_32(dst, shift_amount, 0x4);
+ }
+
void shr(Register dst, Immediate shift_amount) {
shift(dst, shift_amount, 0x5);
}
@@ -1114,8 +1121,8 @@ class Assembler : public Malloced {
// ModR/M byte.
void arithmetic_op(byte opcode, Register dst, Register src);
void arithmetic_op_32(byte opcode, Register dst, Register src);
- void arithmetic_op_32(byte opcode, const Operand& dst, Register src);
- void arithmetic_op(byte opcode, Register reg, const Operand& op);
+ void arithmetic_op_32(byte opcode, Register reg, const Operand& rm_reg);
+ void arithmetic_op(byte opcode, Register reg, const Operand& rm_reg);
void immediate_arithmetic_op(byte subcode, Register dst, Immediate src);
void immediate_arithmetic_op(byte subcode, const Operand& dst, Immediate src);
// Operate on a 32-bit word in memory or register.
diff --git a/V8Binding/v8/src/x64/codegen-x64.cc b/V8Binding/v8/src/x64/codegen-x64.cc
index e3e32e6..9ed7e74 100644
--- a/V8Binding/v8/src/x64/codegen-x64.cc
+++ b/V8Binding/v8/src/x64/codegen-x64.cc
@@ -5321,6 +5321,7 @@ void Reference::GetValue(TypeofState typeof_state) {
// patch the map check if appropriate.
// TODO(x64): Implement inlined loads for keyed properties.
+ // Make sure to load length field as a 32-bit quantity.
// Comment cmnt(masm, "[ Load from keyed Property");
RelocInfo::Mode mode = is_global
diff --git a/V8Binding/v8/src/x64/debug-x64.cc b/V8Binding/v8/src/x64/debug-x64.cc
index e94e781..177eb90 100644
--- a/V8Binding/v8/src/x64/debug-x64.cc
+++ b/V8Binding/v8/src/x64/debug-x64.cc
@@ -80,6 +80,21 @@ void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) {
masm->int3(); // UNIMPLEMENTED
}
+void BreakLocationIterator::ClearDebugBreakAtReturn() {
+ // TODO(X64): Implement this when we start setting Debug breaks.
+ UNIMPLEMENTED();
+}
+
+bool BreakLocationIterator::IsDebugBreakAtReturn() {
+ // TODO(X64): Implement this when we start setting Debug breaks.
+ UNIMPLEMENTED();
+ return false;
+}
+
+void BreakLocationIterator::SetDebugBreakAtReturn() {
+ UNIMPLEMENTED();
+}
+
#endif // ENABLE_DEBUGGER_SUPPORT
} } // namespace v8::internal
diff --git a/V8Binding/v8/src/x64/disasm-x64.cc b/V8Binding/v8/src/x64/disasm-x64.cc
index f962c01..83fa9cd 100644
--- a/V8Binding/v8/src/x64/disasm-x64.cc
+++ b/V8Binding/v8/src/x64/disasm-x64.cc
@@ -34,8 +34,15 @@
namespace disasm {
-enum OperandOrder {
- UNSET_OP_ORDER = 0, REG_OPER_OP_ORDER, OPER_REG_OP_ORDER
+enum OperandType {
+ UNSET_OP_ORDER = 0,
+ // Operand size decides between 16, 32 and 64 bit operands.
+ REG_OPER_OP_ORDER = 1, // Register destination, operand source.
+ OPER_REG_OP_ORDER = 2, // Operand destination, register source.
+ // Fixed 8-bit operands.
+ BYTE_SIZE_OPERAND_FLAG = 4,
+ BYTE_REG_OPER_OP_ORDER = REG_OPER_OP_ORDER | BYTE_SIZE_OPERAND_FLAG,
+ BYTE_OPER_REG_OP_ORDER = OPER_REG_OP_ORDER | BYTE_SIZE_OPERAND_FLAG
};
//------------------------------------------------------------------
@@ -43,28 +50,53 @@ enum OperandOrder {
//------------------------------------------------------------------
struct ByteMnemonic {
int b; // -1 terminates, otherwise must be in range (0..255)
- OperandOrder op_order_;
+ OperandType op_order_;
const char* mnem;
};
static ByteMnemonic two_operands_instr[] = {
- { 0x03, REG_OPER_OP_ORDER, "add" },
- { 0x21, OPER_REG_OP_ORDER, "and" },
- { 0x23, REG_OPER_OP_ORDER, "and" },
- { 0x3B, REG_OPER_OP_ORDER, "cmp" },
- { 0x8D, REG_OPER_OP_ORDER, "lea" },
- { 0x09, OPER_REG_OP_ORDER, "or" },
- { 0x0B, REG_OPER_OP_ORDER, "or" },
- { 0x1B, REG_OPER_OP_ORDER, "sbb" },
- { 0x29, OPER_REG_OP_ORDER, "sub" },
- { 0x2B, REG_OPER_OP_ORDER, "sub" },
- { 0x85, REG_OPER_OP_ORDER, "test" },
- { 0x31, OPER_REG_OP_ORDER, "xor" },
- { 0x33, REG_OPER_OP_ORDER, "xor" },
- { 0x87, REG_OPER_OP_ORDER, "xchg" },
- { 0x8A, REG_OPER_OP_ORDER, "movb" },
- { 0x8B, REG_OPER_OP_ORDER, "mov" },
+ { 0x00, BYTE_OPER_REG_OP_ORDER, "add" },
+ { 0x01, OPER_REG_OP_ORDER, "add" },
+ { 0x02, BYTE_REG_OPER_OP_ORDER, "add" },
+ { 0x03, REG_OPER_OP_ORDER, "add" },
+ { 0x08, BYTE_OPER_REG_OP_ORDER, "or" },
+ { 0x09, OPER_REG_OP_ORDER, "or" },
+ { 0x0A, BYTE_REG_OPER_OP_ORDER, "or" },
+ { 0x0B, REG_OPER_OP_ORDER, "or" },
+ { 0x10, BYTE_OPER_REG_OP_ORDER, "adc" },
+ { 0x11, OPER_REG_OP_ORDER, "adc" },
+ { 0x12, BYTE_REG_OPER_OP_ORDER, "adc" },
+ { 0x13, REG_OPER_OP_ORDER, "adc" },
+ { 0x18, BYTE_OPER_REG_OP_ORDER, "sbb" },
+ { 0x19, OPER_REG_OP_ORDER, "sbb" },
+ { 0x1A, BYTE_REG_OPER_OP_ORDER, "sbb" },
+ { 0x1B, REG_OPER_OP_ORDER, "sbb" },
+ { 0x20, BYTE_OPER_REG_OP_ORDER, "and" },
+ { 0x21, OPER_REG_OP_ORDER, "and" },
+ { 0x22, BYTE_REG_OPER_OP_ORDER, "and" },
+ { 0x23, REG_OPER_OP_ORDER, "and" },
+ { 0x28, BYTE_OPER_REG_OP_ORDER, "sub" },
+ { 0x29, OPER_REG_OP_ORDER, "sub" },
+ { 0x2A, BYTE_REG_OPER_OP_ORDER, "sub" },
+ { 0x2B, REG_OPER_OP_ORDER, "sub" },
+ { 0x30, BYTE_OPER_REG_OP_ORDER, "xor" },
+ { 0x31, OPER_REG_OP_ORDER, "xor" },
+ { 0x32, BYTE_REG_OPER_OP_ORDER, "xor" },
+ { 0x33, REG_OPER_OP_ORDER, "xor" },
+ { 0x38, BYTE_OPER_REG_OP_ORDER, "cmp" },
+ { 0x39, OPER_REG_OP_ORDER, "cmp" },
+ { 0x3A, BYTE_REG_OPER_OP_ORDER, "cmp" },
+ { 0x3B, REG_OPER_OP_ORDER, "cmp" },
+ { 0x8D, REG_OPER_OP_ORDER, "lea" },
+ { 0x84, BYTE_REG_OPER_OP_ORDER, "test" },
+ { 0x85, REG_OPER_OP_ORDER, "test" },
+ { 0x86, BYTE_REG_OPER_OP_ORDER, "xchg" },
+ { 0x87, REG_OPER_OP_ORDER, "xchg" },
+ { 0x88, BYTE_OPER_REG_OP_ORDER, "mov" },
+ { 0x89, OPER_REG_OP_ORDER, "mov" },
+ { 0x8A, BYTE_REG_OPER_OP_ORDER, "mov" },
+ { 0x8B, REG_OPER_OP_ORDER, "mov" },
{ -1, UNSET_OP_ORDER, "" }
};
@@ -97,6 +129,7 @@ static ByteMnemonic short_immediate_instr[] = {
{ 0x05, UNSET_OP_ORDER, "add" },
{ 0x0D, UNSET_OP_ORDER, "or" },
{ 0x15, UNSET_OP_ORDER, "adc" },
+ { 0x1D, UNSET_OP_ORDER, "sbb" },
{ 0x25, UNSET_OP_ORDER, "and" },
{ 0x2D, UNSET_OP_ORDER, "sub" },
{ 0x35, UNSET_OP_ORDER, "xor" },
@@ -127,7 +160,8 @@ enum InstructionType {
struct InstructionDesc {
const char* mnem;
InstructionType type;
- OperandOrder op_order_;
+ OperandType op_order_;
+ bool byte_size_operation; // Fixed 8-bit operation.
};
@@ -143,7 +177,7 @@ class InstructionTable {
void Clear();
void Init();
void CopyTable(ByteMnemonic bm[], InstructionType type);
- void SetTableRange(InstructionType type, byte start, byte end,
+ void SetTableRange(InstructionType type, byte start, byte end, bool byte_size,
const char* mnem);
void AddJumpConditionalShort();
};
@@ -157,9 +191,10 @@ InstructionTable::InstructionTable() {
void InstructionTable::Clear() {
for (int i = 0; i < 256; i++) {
- instructions_[i].mnem = "";
+ instructions_[i].mnem = "(bad)";
instructions_[i].type = NO_INSTR;
instructions_[i].op_order_ = UNSET_OP_ORDER;
+ instructions_[i].byte_size_operation = false;
}
}
@@ -170,9 +205,9 @@ void InstructionTable::Init() {
CopyTable(call_jump_instr, CALL_JUMP_INSTR);
CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
AddJumpConditionalShort();
- SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, "push");
- SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, "pop");
- SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov");
+ SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, false, "push");
+ SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, false, "pop");
+ SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, false, "mov");
}
@@ -180,20 +215,27 @@ void InstructionTable::CopyTable(ByteMnemonic bm[], InstructionType type) {
for (int i = 0; bm[i].b >= 0; i++) {
InstructionDesc* id = &instructions_[bm[i].b];
id->mnem = bm[i].mnem;
- id->op_order_ = bm[i].op_order_;
- assert(id->type == NO_INSTR); // Information already entered
+ OperandType op_order = bm[i].op_order_;
+ id->op_order_ =
+ static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG);
+ assert(id->type == NO_INSTR); // Information not already entered
id->type = type;
+ id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0);
}
}
-void InstructionTable::SetTableRange(InstructionType type, byte start,
- byte end, const char* mnem) {
+void InstructionTable::SetTableRange(InstructionType type,
+ byte start,
+ byte end,
+ bool byte_size,
+ const char* mnem) {
for (byte b = start; b <= end; b++) {
InstructionDesc* id = &instructions_[b];
assert(id->type == NO_INSTR); // Information already entered
id->mnem = mnem;
id->type = type;
+ id->byte_size_operation = byte_size;
}
}
@@ -211,13 +253,16 @@ void InstructionTable::AddJumpConditionalShort() {
static InstructionTable instruction_table;
-// The X64 disassembler implementation.
+//------------------------------------------------------------------------------
+// DisassemblerX64 implementation.
+
enum UnimplementedOpcodeAction {
CONTINUE_ON_UNIMPLEMENTED_OPCODE,
ABORT_ON_UNIMPLEMENTED_OPCODE
};
-
+// A new DisassemblerX64 object is created to disassemble each instruction.
+// The object can only disassemble a single instruction.
class DisassemblerX64 {
public:
DisassemblerX64(const NameConverter& converter,
@@ -228,7 +273,9 @@ class DisassemblerX64 {
abort_on_unimplemented_(
unimplemented_action == ABORT_ON_UNIMPLEMENTED_OPCODE),
rex_(0),
- operand_size_(0) {
+ operand_size_(0),
+ group_1_prefix_(0),
+ byte_size_operand_(false) {
tmp_buffer_[0] = '\0';
}
@@ -240,6 +287,12 @@ class DisassemblerX64 {
int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
private:
+ enum OperandSize {
+ BYTE_SIZE = 0,
+ WORD_SIZE = 1,
+ DOUBLEWORD_SIZE = 2,
+ QUADWORD_SIZE = 3
+ };
const NameConverter& converter_;
v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
@@ -247,12 +300,10 @@ class DisassemblerX64 {
bool abort_on_unimplemented_;
// Prefixes parsed
byte rex_;
- byte operand_size_;
-
- void setOperandSizePrefix(byte prefix) {
- ASSERT_EQ(0x66, prefix);
- operand_size_ = prefix;
- }
+ byte operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0.
+ byte group_1_prefix_; // 0xF2, 0xF3, or (if no group 1 prefix is present) 0.
+ // Byte size operand override.
+ bool byte_size_operand_;
void setRex(byte rex) {
ASSERT_EQ(0x40, rex & 0xF0);
@@ -272,12 +323,15 @@ class DisassemblerX64 {
bool rex_w() { return (rex_ & 0x08) != 0; }
- int operand_size() {
- return rex_w() ? 64 : (operand_size_ != 0) ? 16 : 32;
+ OperandSize operand_size() {
+ if (byte_size_operand_) return BYTE_SIZE;
+ if (rex_w()) return QUADWORD_SIZE;
+ if (operand_size_ != 0) return WORD_SIZE;
+ return DOUBLEWORD_SIZE;
}
char operand_size_code() {
- return rex_w() ? 'q' : (operand_size_ != 0) ? 'w' : 'l';
+ return "bwlq"[operand_size()];
}
const char* NameOfCPURegister(int reg) const {
@@ -312,7 +366,7 @@ class DisassemblerX64 {
int* base) {
*scale = (data >> 6) & 3;
*index = ((data >> 3) & 7) | (rex_x() ? 8 : 0);
- *base = data & 7 | (rex_b() ? 8 : 0);
+ *base = (data & 7) | (rex_b() ? 8 : 0);
}
typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const;
@@ -322,11 +376,14 @@ class DisassemblerX64 {
int PrintRightOperand(byte* modrmp);
int PrintRightByteOperand(byte* modrmp);
int PrintOperands(const char* mnem,
- OperandOrder op_order,
+ OperandType op_order,
byte* data);
+ int PrintImmediate(byte* data, OperandSize size);
int PrintImmediateOp(byte* data);
+ const char* TwoByteMnemonic(byte opcode);
+ int TwoByteOpcodeInstruction(byte* data);
int F7Instruction(byte* data);
- int D1D3C1Instruction(byte* data);
+ int ShiftInstruction(byte* data);
int JumpShort(byte* data);
int JumpConditional(byte* data);
int JumpConditionalShort(byte* data);
@@ -336,7 +393,7 @@ class DisassemblerX64 {
void UnimplementedInstruction() {
if (abort_on_unimplemented_) {
- UNIMPLEMENTED();
+ CHECK(false);
} else {
AppendToBuffer("'Unimplemented Instruction'");
}
@@ -451,6 +508,36 @@ int DisassemblerX64::PrintRightOperandHelper(
}
+int DisassemblerX64::PrintImmediate(byte* data, OperandSize size) {
+ int64_t value;
+ int count;
+ switch (size) {
+ case BYTE_SIZE:
+ value = *data;
+ count = 1;
+ break;
+ case WORD_SIZE:
+ value = *reinterpret_cast<int16_t*>(data);
+ count = 2;
+ break;
+ case DOUBLEWORD_SIZE:
+ value = *reinterpret_cast<uint32_t*>(data);
+ count = 4;
+ break;
+ case QUADWORD_SIZE:
+ value = *reinterpret_cast<int32_t*>(data);
+ count = 4;
+ break;
+ default:
+ UNREACHABLE();
+ value = 0; // Initialize variables on all paths to satisfy the compiler.
+ count = 0;
+ }
+ AppendToBuffer(V8_PTR_PREFIX"x", value);
+ return count;
+}
+
+
int DisassemblerX64::PrintRightOperand(byte* modrmp) {
return PrintRightOperandHelper(modrmp,
&DisassemblerX64::NameOfCPURegister);
@@ -466,25 +553,30 @@ int DisassemblerX64::PrintRightByteOperand(byte* modrmp) {
// Returns number of bytes used including the current *data.
// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
int DisassemblerX64::PrintOperands(const char* mnem,
- OperandOrder op_order,
+ OperandType op_order,
byte* data) {
byte modrm = *data;
int mod, regop, rm;
get_modrm(modrm, &mod, &regop, &rm);
int advance = 0;
+ const char* register_name =
+ byte_size_operand_ ? NameOfByteCPURegister(regop)
+ : NameOfCPURegister(regop);
switch (op_order) {
case REG_OPER_OP_ORDER: {
AppendToBuffer("%s%c %s,",
mnem,
operand_size_code(),
- NameOfCPURegister(regop));
- advance = PrintRightOperand(data);
+ register_name);
+ advance = byte_size_operand_ ? PrintRightByteOperand(data)
+ : PrintRightOperand(data);
break;
}
case OPER_REG_OP_ORDER: {
AppendToBuffer("%s%c ", mnem, operand_size_code());
- advance = PrintRightOperand(data);
- AppendToBuffer(",%s", NameOfCPURegister(regop));
+ advance = byte_size_operand_ ? PrintRightByteOperand(data)
+ : PrintRightOperand(data);
+ AppendToBuffer(",%s", register_name);
break;
}
default:
@@ -498,7 +590,7 @@ int DisassemblerX64::PrintOperands(const char* mnem,
// Returns number of bytes used by machine instruction, including *data byte.
// Writes immediate instructions to 'tmp_buffer_'.
int DisassemblerX64::PrintImmediateOp(byte* data) {
- bool sign_extension_bit = (*data & 0x02) != 0;
+ bool byte_size_immediate = (*data & 0x02) != 0;
byte modrm = *(data + 1);
int mod, regop, rm;
get_modrm(modrm, &mod, &regop, &rm);
@@ -528,15 +620,12 @@ int DisassemblerX64::PrintImmediateOp(byte* data) {
default:
UnimplementedInstruction();
}
- AppendToBuffer("%s ", mnem);
+ AppendToBuffer("%s%c ", mnem, operand_size_code());
int count = PrintRightOperand(data + 1);
- if (sign_extension_bit) {
- AppendToBuffer(",0x%x", *(data + 1 + count));
- return 1 + count + 1 /*int8*/;
- } else {
- AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
- return 1 + count + 4 /*int32_t*/;
- }
+ AppendToBuffer(",0x");
+ OperandSize immediate_size = byte_size_immediate ? BYTE_SIZE : operand_size();
+ count += PrintImmediate(data + 1 + count, immediate_size);
+ return 1 + count;
}
@@ -589,78 +678,65 @@ int DisassemblerX64::F7Instruction(byte* data) {
}
-int DisassemblerX64::D1D3C1Instruction(byte* data) {
- byte op = *data;
- assert(op == 0xD1 || op == 0xD3 || op == 0xC1);
+int DisassemblerX64::ShiftInstruction(byte* data) {
+ byte op = *data & (~1);
+ if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
+ UnimplementedInstruction();
+ return 1;
+ }
byte modrm = *(data + 1);
int mod, regop, rm;
get_modrm(modrm, &mod, &regop, &rm);
ASSERT(regop < 8);
int imm8 = -1;
int num_bytes = 2;
- if (mod == 3) {
- const char* mnem = NULL;
- if (op == 0xD1) {
- imm8 = 1;
- switch (regop) {
- case 2:
- mnem = "rcl";
- break;
- case 7:
- mnem = "sar";
- break;
- case 4:
- mnem = "shl";
- break;
- default:
- UnimplementedInstruction();
- }
- } else if (op == 0xC1) {
- imm8 = *(data + 2);
- num_bytes = 3;
- switch (regop) {
- case 2:
- mnem = "rcl";
- break;
- case 4:
- mnem = "shl";
- break;
- case 5:
- mnem = "shr";
- break;
- case 7:
- mnem = "sar";
- break;
- default:
- UnimplementedInstruction();
- }
- } else if (op == 0xD3) {
- switch (regop) {
- case 4:
- mnem = "shl";
- break;
- case 5:
- mnem = "shr";
- break;
- case 7:
- mnem = "sar";
- break;
- default:
- UnimplementedInstruction();
- }
- }
- assert(mnem != NULL);
- AppendToBuffer("%s%c %s,",
- mnem,
- operand_size_code(),
- NameOfCPURegister(rm));
- if (imm8 > 0) {
- AppendToBuffer("%d", imm8);
- } else {
- AppendToBuffer("cl");
- }
- } else {
+ if (mod != 3) {
UnimplementedInstruction();
+ return num_bytes;
+ }
+ const char* mnem = NULL;
+ switch (regop) {
+ case 0:
+ mnem = "rol";
+ break;
+ case 1:
+ mnem = "ror";
+ break;
+ case 2:
+ mnem = "rcl";
+ break;
+ case 3:
+ mnem = "rcr";
+ break;
+ case 4:
+ mnem = "shl";
+ break;
+ case 5:
+ mnem = "shr";
+ break;
+ case 7:
+ mnem = "sar";
+ break;
+ default:
+ UnimplementedInstruction();
+ return num_bytes;
+ }
+ assert(mnem != NULL);
+ if (op == 0xD0) {
+ imm8 = 1;
+ } else if (op == 0xC0) {
+ imm8 = *(data + 2);
+ num_bytes = 3;
+ }
+ AppendToBuffer("%s%c %s,",
+ mnem,
+ operand_size_code(),
+ byte_size_operand_ ? NameOfByteCPURegister(rm)
+ : NameOfCPURegister(rm));
+ if (op == 0xD2) {
+ AppendToBuffer("cl");
+ } else {
+ AppendToBuffer("%d", imm8);
}
return num_bytes;
}
@@ -716,20 +792,14 @@ int DisassemblerX64::FPUInstruction(byte* data) {
if (b1 == 0xD9) {
const char* mnem = NULL;
switch (b2) {
- case 0xE8:
- mnem = "fld1";
- break;
- case 0xEE:
- mnem = "fldz";
+ case 0xE0:
+ mnem = "fchs";
break;
case 0xE1:
mnem = "fabs";
break;
- case 0xE0:
- mnem = "fchs";
- break;
- case 0xF8:
- mnem = "fprem";
+ case 0xE4:
+ mnem = "ftst";
break;
case 0xF5:
mnem = "fprem1";
@@ -737,8 +807,14 @@ int DisassemblerX64::FPUInstruction(byte* data) {
case 0xF7:
mnem = "fincstp";
break;
- case 0xE4:
- mnem = "ftst";
+ case 0xE8:
+ mnem = "fld1";
+ break;
+ case 0xEE:
+ mnem = "fldz";
+ break;
+ case 0xF8:
+ mnem = "fprem";
break;
}
if (mnem != NULL) {
@@ -862,38 +938,146 @@ int DisassemblerX64::FPUInstruction(byte* data) {
return 2;
}
-// Mnemonics for instructions 0xF0 byte.
+
+// Handle all two-byte opcodes, which start with 0x0F.
+// These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix.
+// We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A.
+int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
+ byte opcode = *(data + 1);
+ byte* current = data + 2;
+ // At return, "current" points to the start of the next instruction.
+ const char* mnemonic = TwoByteMnemonic(opcode);
+ if (opcode == 0x1F) {
+ // NOP
+ int mod, regop, rm;
+ get_modrm(*current, &mod, &regop, &rm);
+ current++;
+ if (regop == 4) { // SIB byte present.
+ current++;
+ }
+ if (mod == 1) { // Byte displacement.
+ current += 1;
+ } else if (mod == 2) { // 32-bit displacement.
+ current += 4;
+ } // else no immediate displacement.
+ AppendToBuffer("nop");
+
+ } else if (opcode == 0xA2 || opcode == 0x31) {
+ // RDTSC or CPUID
+ AppendToBuffer("%s", mnemonic);
+
+ } else if ((opcode & 0xF0) == 0x80) {
+ // Jcc: Conditional jump (branch).
+ current = data + JumpConditional(data);
+
+ } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
+ opcode == 0xB7 || opcode == 0xAF) {
+ // Size-extending moves, IMUL.
+ current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
+
+ } else if ((opcode & 0xF0) == 0x90) {
+ // SETcc: Set byte on condition. Needs pointer to beginning of instruction.
+ current = data + SetCC(data);
+
+ } else if (opcode == 0xAB || opcode == 0xA5 || opcode == 0xAD) {
+ // SHLD, SHRD (double-precision shift), BTS (bit set).
+ AppendToBuffer("%s ", mnemonic);
+ int mod, regop, rm;
+ get_modrm(*current, &mod, &regop, &rm);
+ current += PrintRightOperand(current);
+ if (opcode == 0xAB) {
+ AppendToBuffer(",%s", NameOfCPURegister(regop));
+ } else {
+ AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
+ }
+ } else if (group_1_prefix_ == 0xF2) {
+ // Beginning of instructions with prefix 0xF2.
+
+ if (opcode == 0x11 || opcode == 0x10) {
+ // MOVSD: Move scalar double-precision fp to/from/between XMM registers.
+ AppendToBuffer("movsd ");
+ int mod, regop, rm;
+ get_modrm(*current, &mod, &regop, &rm);
+ if (opcode == 0x11) {
+ current += PrintRightOperand(current);
+ AppendToBuffer(",%s", NameOfXMMRegister(regop));
+ } else {
+ AppendToBuffer("%s,", NameOfXMMRegister(regop));
+ current += PrintRightOperand(current);
+ }
+ } else if (opcode == 0x2A) {
+ // CVTSI2SD: integer to XMM double conversion.
+ int mod, regop, rm;
+ get_modrm(*current, &mod, &regop, &rm);
+ AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
+ data += PrintRightOperand(data);
+ } else if ((opcode & 0xF8) == 0x58) {
+ // XMM arithmetic. Mnemonic was retrieved at the start of this function.
+ int mod, regop, rm;
+ get_modrm(*current, &mod, &regop, &rm);
+ AppendToBuffer("%s %s,%s", mnemonic, NameOfXMMRegister(regop),
+ NameOfXMMRegister(rm));
+ } else {
+ UnimplementedInstruction();
+ }
+ } else if (opcode == 0x2C && group_1_prefix_ == 0xF3) {
+ // Instruction with prefix 0xF3.
+
+ // CVTTSS2SI: Convert scalar single-precision FP to dword integer.
+ // Assert that mod is not 3, so source is memory, not an XMM register.
+ ASSERT((*current & 0xC0) != 0xC0);
+ current += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, current);
+ } else {
+ UnimplementedInstruction();
+ }
+ return current - data;
+}
+
+
+// Mnemonics for two-byte opcode instructions starting with 0x0F.
+// The argument is the second byte of the two-byte opcode.
// Returns NULL if the instruction is not handled here.
-static const char* F0Mnem(byte f0byte) {
- switch (f0byte) {
+const char* DisassemblerX64::TwoByteMnemonic(byte opcode) {
+ switch (opcode) {
case 0x1F:
return "nop";
+ case 0x2A: // F2 prefix.
+ return "cvtsi2sd";
case 0x31:
return "rdtsc";
+ case 0x58: // F2 prefix.
+ return "addsd";
+ case 0x59: // F2 prefix.
+ return "mulsd";
+ case 0x5C: // F2 prefix.
+ return "subsd";
+ case 0x5E: // F2 prefix.
+ return "divsd";
case 0xA2:
return "cpuid";
- case 0xBE:
- return "movsxb";
- case 0xBF:
- return "movsxw";
- case 0xB6:
- return "movzxb";
- case 0xB7:
- return "movzxw";
- case 0xAF:
- return "imul";
case 0xA5:
return "shld";
- case 0xAD:
- return "shrd";
case 0xAB:
return "bts";
+ case 0xAD:
+ return "shrd";
+ case 0xAF:
+ return "imul";
+ case 0xB6:
+ return "movzxb";
+ case 0xB7:
+ return "movzxw";
+ case 0xBE:
+ return "movsxb";
+ case 0xBF:
+ return "movsxw";
default:
return NULL;
}
}
-// Disassembled instruction '*instr' and writes it into 'out_buffer'.
+
+// Disassembles the instruction at instr, and writes it into out_buffer.
int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
byte* instr) {
tmp_buffer_pos_ = 0; // starting to write as position 0
@@ -905,19 +1089,21 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
// Scan for prefixes.
while (true) {
current = *data;
- if (current == 0x66) {
- setOperandSizePrefix(current);
- data++;
- } else if ((current & 0xF0) == 0x40) {
+ if (current == 0x66) { // Group 3 prefix.
+ operand_size_ = current;
+ } else if ((current & 0xF0) == 0x40) { // REX prefix.
setRex(current);
if (rex_w()) AppendToBuffer("REX.W ");
- data++;
- } else {
+ } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix.
+ group_1_prefix_ = current;
+ } else { // Not a prefix - an opcode.
break;
}
+ data++;
}
const InstructionDesc& idesc = instruction_table.Get(current);
+ byte_size_operand_ = idesc.byte_size_operation;
switch (idesc.type) {
case ZERO_OPERANDS_INSTR:
AppendToBuffer(idesc.mnem);
@@ -949,15 +1135,15 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
case MOVE_REG_INSTR: {
byte* addr = NULL;
switch (operand_size()) {
- case 16:
+ case WORD_SIZE:
addr = reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1));
data += 3;
break;
- case 32:
+ case DOUBLEWORD_SIZE:
addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
data += 5;
break;
- case 64:
+ case QUADWORD_SIZE:
addr = reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1));
data += 9;
break;
@@ -1012,8 +1198,8 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
AppendToBuffer("imul %s,%s,0x%x", NameOfCPURegister(regop),
NameOfCPURegister(rm), imm);
data += 2 + (*data == 0x6B ? 1 : 4);
- }
break;
+ }
case 0xF6: {
int mod, regop, rm;
@@ -1024,63 +1210,16 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
UnimplementedInstruction();
}
data += 3;
- }
break;
+ }
case 0x81: // fall through
case 0x83: // 0x81 with sign extension bit set
data += PrintImmediateOp(data);
break;
- case 0x0F: {
- byte f0byte = *(data + 1);
- const char* f0mnem = F0Mnem(f0byte);
- if (f0byte == 0x1F) {
- data += 1;
- byte modrm = *data;
- data += 1;
- if (((modrm >> 3) & 7) == 4) {
- // SIB byte present.
- data += 1;
- }
- int mod = modrm >> 6;
- if (mod == 1) {
- // Byte displacement.
- data += 1;
- } else if (mod == 2) {
- // 32-bit displacement.
- data += 4;
- }
- AppendToBuffer("nop");
- } else if (f0byte == 0xA2 || f0byte == 0x31) {
- AppendToBuffer("%s", f0mnem);
- data += 2;
- } else if ((f0byte & 0xF0) == 0x80) {
- data += JumpConditional(data);
- } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 || f0byte
- == 0xB7 || f0byte == 0xAF) {
- data += 2;
- data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
- } else if ((f0byte & 0xF0) == 0x90) {
- data += SetCC(data);
- } else {
- data += 2;
- if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
- // shrd, shld, bts
- AppendToBuffer("%s ", f0mnem);
- int mod, regop, rm;
- get_modrm(*data, &mod, &regop, &rm);
- data += PrintRightOperand(data);
- if (f0byte == 0xAB) {
- AppendToBuffer(",%s", NameOfCPURegister(regop));
- } else {
- AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
- }
- } else {
- UnimplementedInstruction();
- }
- }
- }
+ case 0x0F:
+ data += TwoByteOpcodeInstruction(data);
break;
case 0x8F: {
@@ -1170,13 +1309,13 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
case 0x95:
case 0x96:
case 0x97: {
- int reg = current & 0x7 | (rex_b() ? 8 : 0);
+ int reg = (current & 0x7) | (rex_b() ? 8 : 0);
if (reg == 0) {
AppendToBuffer("nop"); // Common name for xchg rax,rax.
} else {
AppendToBuffer("xchg%c rax, %s",
operand_size_code(),
- NameOfByteCPURegister(reg));
+ NameOfCPURegister(reg));
}
}
@@ -1209,17 +1348,39 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
data += 2;
break;
- case 0xA9:
- AppendToBuffer("test%c rax,0x%x", // CHECKME!
+ case 0xA9: {
+ int64_t value = 0;
+ switch (operand_size()) {
+ case WORD_SIZE:
+ value = *reinterpret_cast<uint16_t*>(data + 1);
+ data += 3;
+ break;
+ case DOUBLEWORD_SIZE:
+ value = *reinterpret_cast<uint32_t*>(data + 1);
+ data += 5;
+ break;
+ case QUADWORD_SIZE:
+ value = *reinterpret_cast<int32_t*>(data + 1);
+ data += 5;
+ break;
+ default:
+ UNREACHABLE();
+ }
+ AppendToBuffer("test%c rax,0x%"V8_PTR_PREFIX"ux",
operand_size_code(),
- *reinterpret_cast<int32_t*>(data + 1));
- data += 5;
+ value);
break;
-
+ }
case 0xD1: // fall through
case 0xD3: // fall through
case 0xC1:
- data += D1D3C1Instruction(data);
+ data += ShiftInstruction(data);
+ break;
+ case 0xD0: // fall through
+ case 0xD2: // fall through
+ case 0xC0:
+ byte_size_operand_ = true;
+ data += ShiftInstruction(data);
break;
case 0xD9: // fall through
@@ -1236,73 +1397,13 @@ int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
data += JumpShort(data);
break;
- case 0xF2:
- if (*(data + 1) == 0x0F) {
- byte b2 = *(data + 2);
- if (b2 == 0x11) {
- AppendToBuffer("movsd ");
- data += 3;
- int mod, regop, rm;
- get_modrm(*data, &mod, &regop, &rm);
- data += PrintRightOperand(data);
- AppendToBuffer(",%s", NameOfXMMRegister(regop));
- } else if (b2 == 0x10) {
- data += 3;
- int mod, regop, rm;
- get_modrm(*data, &mod, &regop, &rm);
- AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
- data += PrintRightOperand(data);
- } else {
- const char* mnem = "?";
- switch (b2) {
- case 0x2A:
- mnem = "cvtsi2sd";
- break;
- case 0x58:
- mnem = "addsd";
- break;
- case 0x59:
- mnem = "mulsd";
- break;
- case 0x5C:
- mnem = "subsd";
- break;
- case 0x5E:
- mnem = "divsd";
- break;
- }
- data += 3;
- int mod, regop, rm;
- get_modrm(*data, &mod, &regop, &rm);
- if (b2 == 0x2A) {
- AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
- data += PrintRightOperand(data);
- } else {
- AppendToBuffer("%s %s,%s", mnem, NameOfXMMRegister(regop),
- NameOfXMMRegister(rm));
- data++;
- }
- }
- } else {
- UnimplementedInstruction();
- }
- break;
-
- case 0xF3:
- if (*(data + 1) == 0x0F && *(data + 2) == 0x2C) {
- data += 3;
- data += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, data);
- } else {
- UnimplementedInstruction();
- }
- break;
-
case 0xF7:
data += F7Instruction(data);
break;
default:
UnimplementedInstruction();
+ data += 1;
}
} // !processed
diff --git a/V8Binding/v8/src/x64/ic-x64.cc b/V8Binding/v8/src/x64/ic-x64.cc
index 7b8699f..db74baf 100644
--- a/V8Binding/v8/src/x64/ic-x64.cc
+++ b/V8Binding/v8/src/x64/ic-x64.cc
@@ -43,11 +43,11 @@ namespace internal {
void KeyedLoadIC::ClearInlinedVersion(Address address) {
- UNIMPLEMENTED();
+ // TODO(X64): Implement this when LoadIC is enabled.
}
void KeyedStoreIC::ClearInlinedVersion(Address address) {
- UNIMPLEMENTED();
+ // TODO(X64): Implement this when LoadIC is enabled.
}
void KeyedStoreIC::RestoreInlinedVersion(Address address) {
@@ -78,22 +78,32 @@ void KeyedLoadIC::Generate(MacroAssembler* masm,
void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
- masm->int3(); // UNIMPLEMENTED.
- masm->movq(kScratchRegister, Immediate(0xC0AB)); // Debugging aid.
+ // ----------- S t a t e -------------
+ // -- rsp[0] : return address
+ // -- rsp[8] : name
+ // -- rsp[16] : receiver
+ // -----------------------------------
+
+ Generate(masm, ExternalReference(Runtime::kKeyedGetProperty));
}
void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
- masm->int3(); // UNIMPLEMENTED.
- masm->movq(kScratchRegister, Immediate(0xC1AB)); // Debugging aid.
+ // ----------- S t a t e -------------
+ // -- rsp[0] : return address
+ // -- rsp[8] : name
+ // -- rsp[16] : receiver
+ // -----------------------------------
+
+ Generate(masm, ExternalReference(Runtime::kKeyedGetProperty));
}
bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
- UNIMPLEMENTED();
+ // Never patch the map in the map check, so the check always fails.
return false;
}
bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
- UNIMPLEMENTED();
+ // Never patch the map in the map check, so the check always fails.
return false;
}
@@ -163,13 +173,11 @@ void KeyedStoreIC::Generate(MacroAssembler* masm, ExternalReference const& f) {
}
void KeyedStoreIC::GenerateExtendStorage(MacroAssembler* masm) {
- masm->int3(); // UNIMPLEMENTED.
- masm->movq(kScratchRegister, Immediate(0xC2AB)); // Debugging aid.
+ Generate(masm, ExternalReference(IC_Utility(kKeyedStoreIC_Miss)));
}
void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
- masm->int3(); // UNIMPLEMENTED.
- masm->movq(kScratchRegister, Immediate(0xC3AB)); // Debugging aid.
+ Generate(masm, ExternalReference(IC_Utility(kKeyedStoreIC_Miss)));
}
Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
@@ -228,20 +236,24 @@ void CallIC::Generate(MacroAssembler* masm,
__ InvokeFunction(rdi, actual, JUMP_FUNCTION);
}
-void CallIC::GenerateMegamorphic(MacroAssembler* a, int b) {
- UNIMPLEMENTED();
+void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
+ // Cache miss: Jump to runtime.
+ Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
}
-void CallIC::GenerateNormal(MacroAssembler* a, int b) {
- UNIMPLEMENTED();
+void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
+ // Cache miss: Jump to runtime.
+ Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss)));
}
+// The offset from the inlined patch site to the start of the
+// inlined load instruction.
const int LoadIC::kOffsetToLoadInstruction = 20;
void LoadIC::ClearInlinedVersion(Address address) {
- UNIMPLEMENTED();
+ // TODO(X64): Implement this when LoadIC is enabled.
}
@@ -266,37 +278,54 @@ void LoadIC::Generate(MacroAssembler* masm, ExternalReference const& f) {
void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
- masm->int3(); // UNIMPLEMENTED.
- masm->movq(kScratchRegister, Immediate(0xC4AB)); // Debugging aid.
+ Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
}
void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
- masm->int3(); // UNIMPLEMENTED.
- masm->movq(kScratchRegister, Immediate(0xC5AB)); // Debugging aid.
+ Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
}
+
void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
- masm->int3(); // UNIMPLEMENTED.
- masm->movq(kScratchRegister, Immediate(0xC6AB)); // Debugging aid.
+ // ----------- S t a t e -------------
+ // -- rcx : name
+ // -- rsp[0] : return address
+ // -- rsp[8] : receiver
+ // -----------------------------------
+
+ __ movq(rax, Operand(rsp, kPointerSize));
+
+ // Probe the stub cache.
+ Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
+ NOT_IN_LOOP,
+ MONOMORPHIC);
+ StubCache::GenerateProbe(masm, flags, rax, rcx, rbx, rdx);
+
+ // Cache miss: Jump to runtime.
+ Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
}
+
void LoadIC::GenerateMiss(MacroAssembler* masm) {
- masm->int3(); // UNIMPLEMENTED.
- masm->movq(kScratchRegister, Immediate(0xC7AB)); // Debugging aid.
+ // ----------- S t a t e -------------
+ // -- rcx : name
+ // -- rsp[0] : return address
+ // -- rsp[8] : receiver
+ // -----------------------------------
+
+ Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
}
void LoadIC::GenerateNormal(MacroAssembler* masm) {
- masm->int3(); // UNIMPLEMENTED.
- masm->movq(kScratchRegister, Immediate(0xC8AB)); // Debugging aid.
+ Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
}
void LoadIC::GenerateStringLength(MacroAssembler* masm) {
- masm->int3(); // UNIMPLEMENTED.
- masm->movq(kScratchRegister, Immediate(0xC9AB)); // Debugging aid.
+ Generate(masm, ExternalReference(IC_Utility(kLoadIC_Miss)));
}
bool LoadIC::PatchInlinedLoad(Address address, Object* map, int index) {
- UNIMPLEMENTED();
+ // TODO(X64): Implement this function. Until then, the code is not patched.
return false;
}
@@ -319,13 +348,11 @@ void StoreIC::Generate(MacroAssembler* masm, ExternalReference const& f) {
}
void StoreIC::GenerateExtendStorage(MacroAssembler* masm) {
- masm->int3(); // UNIMPLEMENTED.
- masm->movq(kScratchRegister, Immediate(0xCAAB)); // Debugging aid.
+ Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss)));
}
void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
- masm->int3(); // UNIMPLEMENTED.
- masm->movq(kScratchRegister, Immediate(0xCBAB)); // Debugging aid.
+ Generate(masm, ExternalReference(IC_Utility(kStoreIC_Miss)));
}
diff --git a/V8Binding/v8/src/x64/macro-assembler-x64.cc b/V8Binding/v8/src/x64/macro-assembler-x64.cc
index 099a461..457011b 100644
--- a/V8Binding/v8/src/x64/macro-assembler-x64.cc
+++ b/V8Binding/v8/src/x64/macro-assembler-x64.cc
@@ -882,4 +882,154 @@ void MacroAssembler::LeaveExitFrame(StackFrame::Type type) {
}
+Register MacroAssembler::CheckMaps(JSObject* object, Register object_reg,
+ JSObject* holder, Register holder_reg,
+ Register scratch,
+ Label* miss) {
+ // Make sure there's no overlap between scratch and the other
+ // registers.
+ ASSERT(!scratch.is(object_reg) && !scratch.is(holder_reg));
+
+ // Keep track of the current object in register reg. On the first
+ // iteration, reg is an alias for object_reg, on later iterations,
+ // it is an alias for holder_reg.
+ Register reg = object_reg;
+ int depth = 1;
+
+ // Check the maps in the prototype chain.
+ // Traverse the prototype chain from the object and do map checks.
+ while (object != holder) {
+ depth++;
+
+ // Only global objects and objects that do not require access
+ // checks are allowed in stubs.
+ ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+
+ JSObject* prototype = JSObject::cast(object->GetPrototype());
+ if (Heap::InNewSpace(prototype)) {
+ // Get the map of the current object.
+ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset));
+ Cmp(scratch, Handle<Map>(object->map()));
+ // Branch on the result of the map check.
+ j(not_equal, miss);
+ // Check access rights to the global object. This has to happen
+ // after the map check so that we know that the object is
+ // actually a global object.
+ if (object->IsJSGlobalProxy()) {
+ CheckAccessGlobalProxy(reg, scratch, miss);
+
+ // Restore scratch register to be the map of the object.
+ // We load the prototype from the map in the scratch register.
+ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset));
+ }
+ // The prototype is in new space; we cannot store a reference
+ // to it in the code. Load it from the map.
+ reg = holder_reg; // from now the object is in holder_reg
+ movq(reg, FieldOperand(scratch, Map::kPrototypeOffset));
+
+ } else {
+ // Check the map of the current object.
+ Cmp(FieldOperand(reg, HeapObject::kMapOffset),
+ Handle<Map>(object->map()));
+ // Branch on the result of the map check.
+ j(not_equal, miss);
+ // Check access rights to the global object. This has to happen
+ // after the map check so that we know that the object is
+ // actually a global object.
+ if (object->IsJSGlobalProxy()) {
+ CheckAccessGlobalProxy(reg, scratch, miss);
+ }
+ // The prototype is in old space; load it directly.
+ reg = holder_reg; // from now the object is in holder_reg
+ Move(reg, Handle<JSObject>(prototype));
+ }
+
+ // Go to the next object in the prototype chain.
+ object = prototype;
+ }
+
+ // Check the holder map.
+ Cmp(FieldOperand(reg, HeapObject::kMapOffset),
+ Handle<Map>(holder->map()));
+ j(not_equal, miss);
+
+ // Log the check depth.
+ LOG(IntEvent("check-maps-depth", depth));
+
+ // Perform security check for access to the global object and return
+ // the holder register.
+ ASSERT(object == holder);
+ ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+ if (object->IsJSGlobalProxy()) {
+ CheckAccessGlobalProxy(reg, scratch, miss);
+ }
+ return reg;
+}
+
+
+
+
+void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
+ Register scratch,
+ Label* miss) {
+ Label same_contexts;
+
+ ASSERT(!holder_reg.is(scratch));
+ ASSERT(!scratch.is(kScratchRegister));
+ // Load current lexical context from the stack frame.
+ movq(scratch, Operand(rbp, StandardFrameConstants::kContextOffset));
+
+ // When generating debug code, make sure the lexical context is set.
+ if (FLAG_debug_code) {
+ cmpq(scratch, Immediate(0));
+ Check(not_equal, "we should not have an empty lexical context");
+ }
+ // Load the global context of the current context.
+ int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
+ movq(scratch, FieldOperand(scratch, offset));
+ movq(scratch, FieldOperand(scratch, GlobalObject::kGlobalContextOffset));
+
+ // Check the context is a global context.
+ if (FLAG_debug_code) {
+ Cmp(FieldOperand(scratch, HeapObject::kMapOffset),
+ Factory::global_context_map());
+ Check(equal, "JSGlobalObject::global_context should be a global context.");
+ }
+
+ // Check if both contexts are the same.
+ cmpq(scratch, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
+ j(equal, &same_contexts);
+
+ // Compare security tokens.
+ // Check that the security token in the calling global object is
+ // compatible with the security token in the receiving global
+ // object.
+
+ // Check the context is a global context.
+ if (FLAG_debug_code) {
+ // Preserve original value of holder_reg.
+ push(holder_reg);
+ movq(holder_reg, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
+ Cmp(holder_reg, Factory::null_value());
+ Check(not_equal, "JSGlobalProxy::context() should not be null.");
+
+ // Read the first word and compare to global_context_map(),
+ movq(holder_reg, FieldOperand(holder_reg, HeapObject::kMapOffset));
+ Cmp(holder_reg, Factory::global_context_map());
+ Check(equal, "JSGlobalObject::global_context should be a global context.");
+ pop(holder_reg);
+ }
+
+ movq(kScratchRegister,
+ FieldOperand(holder_reg, JSGlobalProxy::kContextOffset));
+ int token_offset = Context::kHeaderSize +
+ Context::SECURITY_TOKEN_INDEX * kPointerSize;
+ movq(scratch, FieldOperand(scratch, token_offset));
+ cmpq(scratch, FieldOperand(kScratchRegister, token_offset));
+ j(not_equal, miss);
+
+ bind(&same_contexts);
+}
+
+
} } // namespace v8::internal
diff --git a/V8Binding/v8/src/x64/macro-assembler-x64.h b/V8Binding/v8/src/x64/macro-assembler-x64.h
index f13a7ad..2ee6eea 100644
--- a/V8Binding/v8/src/x64/macro-assembler-x64.h
+++ b/V8Binding/v8/src/x64/macro-assembler-x64.h
@@ -212,7 +212,8 @@ class MacroAssembler: public Assembler {
// Generate code for checking access rights - used for security checks
// on access to global objects across environments. The holder register
- // is left untouched, but the scratch register is clobbered.
+ // is left untouched, but the scratch register and kScratchRegister,
+ // which must be different, are clobbered.
void CheckAccessGlobalProxy(Register holder_reg,
Register scratch,
Label* miss);
diff --git a/V8Binding/v8/src/x64/register-allocator-x64-inl.h b/V8Binding/v8/src/x64/register-allocator-x64-inl.h
index 926dd64..54729d6 100644
--- a/V8Binding/v8/src/x64/register-allocator-x64-inl.h
+++ b/V8Binding/v8/src/x64/register-allocator-x64-inl.h
@@ -46,7 +46,7 @@ bool RegisterAllocator::IsReserved(Register reg) {
// non-reserved assembler registers.
int RegisterAllocator::ToNumber(Register reg) {
ASSERT(reg.is_valid() && !IsReserved(reg));
- static const int numbers[] = {
+ const int kNumbers[] = {
0, // rax
2, // rcx
3, // rdx
@@ -64,15 +64,15 @@ int RegisterAllocator::ToNumber(Register reg) {
8, // r14
9 // r15
};
- return numbers[reg.code()];
+ return kNumbers[reg.code()];
}
Register RegisterAllocator::ToRegister(int num) {
ASSERT(num >= 0 && num < kNumRegisters);
- static Register registers[] =
+ const Register kRegisters[] =
{ rax, rbx, rcx, rdx, rdi, r8, r9, r11, r14, r15, r13, r12 };
- return registers[num];
+ return kRegisters[num];
}
diff --git a/V8Binding/v8/src/x64/stub-cache-x64.cc b/V8Binding/v8/src/x64/stub-cache-x64.cc
index c577615..ce7886b 100644
--- a/V8Binding/v8/src/x64/stub-cache-x64.cc
+++ b/V8Binding/v8/src/x64/stub-cache-x64.cc
@@ -36,32 +36,202 @@
namespace v8 {
namespace internal {
-#define __ ACCESS_MASM((&masm_))
-
-
-Object* CallStubCompiler::CompileCallConstant(Object* a,
- JSObject* b,
- JSFunction* c,
- String* d,
- StubCompiler::CheckType e) {
- UNIMPLEMENTED();
- return NULL;
+#define __ ACCESS_MASM((masm()))
+
+
+Object* CallStubCompiler::CompileCallConstant(Object* object,
+ JSObject* holder,
+ JSFunction* function,
+ String* name,
+ StubCompiler::CheckType check) {
+ // ----------- S t a t e -------------
+ // -----------------------------------
+ // rsp[0] return address
+ // rsp[8] argument argc
+ // rsp[16] argument argc - 1
+ // ...
+ // rsp[argc * 8] argument 1
+ // rsp[(argc + 1) * 8] argument 0 = reciever
+ // rsp[(argc + 2) * 8] function name
+
+ Label miss;
+
+ // Get the receiver from the stack.
+ const int argc = arguments().immediate();
+ __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
+
+ // Check that the receiver isn't a smi.
+ if (check != NUMBER_CHECK) {
+ __ testl(rdx, Immediate(kSmiTagMask));
+ __ j(zero, &miss);
+ }
+
+ // Make sure that it's okay not to patch the on stack receiver
+ // unless we're doing a receiver map check.
+ ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
+
+ switch (check) {
+ case RECEIVER_MAP_CHECK:
+ // Check that the maps haven't changed.
+ CheckPrototypes(JSObject::cast(object), rdx, holder,
+ rbx, rcx, name, &miss);
+
+ // Patch the receiver on the stack with the global proxy if
+ // necessary.
+ if (object->IsGlobalObject()) {
+ __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
+ __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
+ }
+ break;
+
+ case STRING_CHECK:
+ // Check that the object is a two-byte string or a symbol.
+ __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rcx);
+ __ j(above_equal, &miss);
+ // Check that the maps starting from the prototype haven't changed.
+ GenerateLoadGlobalFunctionPrototype(masm(),
+ Context::STRING_FUNCTION_INDEX,
+ rcx);
+ CheckPrototypes(JSObject::cast(object->GetPrototype()), rcx, holder,
+ rbx, rdx, name, &miss);
+ break;
+
+ case NUMBER_CHECK: {
+ Label fast;
+ // Check that the object is a smi or a heap number.
+ __ testl(rdx, Immediate(kSmiTagMask));
+ __ j(zero, &fast);
+ __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rcx);
+ __ j(not_equal, &miss);
+ __ bind(&fast);
+ // Check that the maps starting from the prototype haven't changed.
+ GenerateLoadGlobalFunctionPrototype(masm(),
+ Context::NUMBER_FUNCTION_INDEX,
+ rcx);
+ CheckPrototypes(JSObject::cast(object->GetPrototype()), rcx, holder,
+ rbx, rdx, name, &miss);
+ break;
+ }
+
+ case BOOLEAN_CHECK: {
+ Label fast;
+ // Check that the object is a boolean.
+ __ Cmp(rdx, Factory::true_value());
+ __ j(equal, &fast);
+ __ Cmp(rdx, Factory::false_value());
+ __ j(not_equal, &miss);
+ __ bind(&fast);
+ // Check that the maps starting from the prototype haven't changed.
+ GenerateLoadGlobalFunctionPrototype(masm(),
+ Context::BOOLEAN_FUNCTION_INDEX,
+ rcx);
+ CheckPrototypes(JSObject::cast(object->GetPrototype()), rcx, holder,
+ rbx, rdx, name, &miss);
+ break;
+ }
+
+ case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
+ CheckPrototypes(JSObject::cast(object), rdx, holder,
+ rbx, rcx, name, &miss);
+ // Make sure object->elements()->map() != Heap::dictionary_array_map()
+ // Get the elements array of the object.
+ __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
+ // Check that the object is in fast mode (not dictionary).
+ __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset),
+ Factory::hash_table_map());
+ __ j(equal, &miss);
+ break;
+
+ default:
+ UNREACHABLE();
+ }
+
+ // Get the function and setup the context.
+ __ Move(rdi, Handle<JSFunction>(function));
+ __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
+
+ // Jump to the cached code (tail call).
+ ASSERT(function->is_compiled());
+ Handle<Code> code(function->code());
+ ParameterCount expected(function->shared()->formal_parameter_count());
+ __ InvokeCode(code, expected, arguments(),
+ RelocInfo::CODE_TARGET, JUMP_FUNCTION);
+
+ // Handle call cache miss.
+ __ bind(&miss);
+ Handle<Code> ic = ComputeCallMiss(arguments().immediate());
+ __ Jump(ic, RelocInfo::CODE_TARGET);
+
+ // Return the generated code.
+ String* function_name = NULL;
+ if (function->shared()->name()->IsString()) {
+ function_name = String::cast(function->shared()->name());
+ }
+ return GetCode(CONSTANT_FUNCTION, function_name);
}
-Object* CallStubCompiler::CompileCallField(Object* a,
- JSObject* b,
- int c,
- String* d) {
- UNIMPLEMENTED();
- return NULL;
+
+Object* CallStubCompiler::CompileCallField(Object* object,
+ JSObject* holder,
+ int index,
+ String* name) {
+ // ----------- S t a t e -------------
+ // -----------------------------------
+ // rsp[0] return address
+ // rsp[8] argument argc
+ // rsp[16] argument argc - 1
+ // ...
+ // rsp[argc * 8] argument 1
+ // rsp[(argc + 1) * 8] argument 0 = receiver
+ // rsp[(argc + 2) * 8] function name
+ Label miss;
+
+ // Get the receiver from the stack.
+ const int argc = arguments().immediate();
+ __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
+
+ // Check that the receiver isn't a smi.
+ __ testl(rdx, Immediate(kSmiTagMask));
+ __ j(zero, &miss);
+
+ // Do the right check and compute the holder register.
+ Register reg =
+ CheckPrototypes(JSObject::cast(object), rdx, holder,
+ rbx, rcx, name, &miss);
+
+ GenerateFastPropertyLoad(masm(), rdi, reg, holder, index);
+
+ // Check that the function really is a function.
+ __ testl(rdi, Immediate(kSmiTagMask));
+ __ j(zero, &miss);
+ __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rbx);
+ __ j(not_equal, &miss);
+
+ // Patch the receiver on the stack with the global proxy if
+ // necessary.
+ if (object->IsGlobalObject()) {
+ __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
+ __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
+ }
+
+ // Invoke the function.
+ __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION);
+
+ // Handle call cache miss.
+ __ bind(&miss);
+ Handle<Code> ic = ComputeCallMiss(arguments().immediate());
+ __ Jump(ic, RelocInfo::CODE_TARGET);
+
+ // Return the generated code.
+ return GetCode(FIELD, name);
}
Object* CallStubCompiler::CompileCallInterceptor(Object* a,
JSObject* b,
String* c) {
- UNIMPLEMENTED();
- return NULL;
+ // TODO(X64): Implement a real stub.
+ return Failure::InternalError();
}
@@ -71,8 +241,69 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
JSGlobalPropertyCell* cell,
JSFunction* function,
String* name) {
- UNIMPLEMENTED();
- return NULL;
+ // ----------- S t a t e -------------
+ // -----------------------------------
+ // rsp[0] return address
+ // rsp[8] argument argc
+ // rsp[16] argument argc - 1
+ // ...
+ // rsp[argc * 8] argument 1
+ // rsp[(argc + 1) * 8] argument 0 = receiver
+ // rsp[(argc + 2) * 8] function name
+ Label miss;
+
+ __ IncrementCounter(&Counters::call_global_inline, 1);
+
+ // Get the number of arguments.
+ const int argc = arguments().immediate();
+
+ // Get the receiver from the stack.
+ __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
+
+ // If the object is the holder then we know that it's a global
+ // object which can only happen for contextual calls. In this case,
+ // the receiver cannot be a smi.
+ if (object != holder) {
+ __ testl(rdx, Immediate(kSmiTagMask));
+ __ j(zero, &miss);
+ }
+
+ // Check that the maps haven't changed.
+ CheckPrototypes(object, rdx, holder, rbx, rcx, name, &miss);
+
+ // Get the value from the cell.
+ __ Move(rdi, Handle<JSGlobalPropertyCell>(cell));
+ __ movq(rdi, FieldOperand(rdi, JSGlobalPropertyCell::kValueOffset));
+
+ // Check that the cell contains the same function.
+ __ Cmp(rdi, Handle<JSFunction>(function));
+ __ j(not_equal, &miss);
+
+ // Patch the receiver on the stack with the global proxy.
+ if (object->IsGlobalObject()) {
+ __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
+ __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
+ }
+
+ // Setup the context (function already in edi).
+ __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
+
+ // Jump to the cached code (tail call).
+ ASSERT(function->is_compiled());
+ Handle<Code> code(function->code());
+ ParameterCount expected(function->shared()->formal_parameter_count());
+ __ InvokeCode(code, expected, arguments(),
+ RelocInfo::CODE_TARGET, JUMP_FUNCTION);
+
+ // Handle call cache miss.
+ __ bind(&miss);
+ __ DecrementCounter(&Counters::call_global_inline, 1);
+ __ IncrementCounter(&Counters::call_global_inline_miss, 1);
+ Handle<Code> ic = ComputeCallMiss(arguments().immediate());
+ __ Jump(ic, RelocInfo::CODE_TARGET);
+
+ // Return the generated code.
+ return GetCode(NORMAL, name);
}
@@ -80,34 +311,58 @@ Object* LoadStubCompiler::CompileLoadCallback(JSObject* a,
JSObject* b,
AccessorInfo* c,
String* d) {
- UNIMPLEMENTED();
- return NULL;
+ // TODO(X64): Implement a real stub.
+ return Failure::InternalError();
}
-Object* LoadStubCompiler::CompileLoadConstant(JSObject* a,
- JSObject* b,
- Object* c,
- String* d) {
- UNIMPLEMENTED();
- return NULL;
+Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
+ JSObject* holder,
+ Object* value,
+ String* name) {
+ // ----------- S t a t e -------------
+ // -- rcx : name
+ // -- rsp[0] : return address
+ // -- rsp[8] : receiver
+ // -----------------------------------
+ Label miss;
+
+ __ movq(rax, (Operand(rsp, kPointerSize)));
+ GenerateLoadConstant(object, holder, rax, rbx, rdx, value, name, &miss);
+ __ bind(&miss);
+ GenerateLoadMiss(masm(), Code::LOAD_IC);
+
+ // Return the generated code.
+ return GetCode(CONSTANT_FUNCTION, name);
}
-Object* LoadStubCompiler::CompileLoadField(JSObject* a,
- JSObject* b,
- int c,
- String* d) {
- UNIMPLEMENTED();
- return NULL;
+Object* LoadStubCompiler::CompileLoadField(JSObject* object,
+ JSObject* holder,
+ int index,
+ String* name) {
+ // ----------- S t a t e -------------
+ // -- rcx : name
+ // -- rsp[0] : return address
+ // -- rsp[8] : receiver
+ // -----------------------------------
+ Label miss;
+
+ __ movq(rax, (Operand(rsp, kPointerSize)));
+ GenerateLoadField(object, holder, rax, rbx, rdx, index, name, &miss);
+ __ bind(&miss);
+ GenerateLoadMiss(masm(), Code::LOAD_IC);
+
+ // Return the generated code.
+ return GetCode(FIELD, name);
}
Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* a,
JSObject* b,
String* c) {
- UNIMPLEMENTED();
- return NULL;
+ // TODO(X64): Implement a real stub.
+ return Failure::InternalError();
}
@@ -116,8 +371,51 @@ Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
JSGlobalPropertyCell* cell,
String* name,
bool is_dont_delete) {
- UNIMPLEMENTED();
- return NULL;
+ // ----------- S t a t e -------------
+ // -- rcx : name
+ // -- rsp[0] : return address
+ // -- rsp[8] : receiver
+ // -----------------------------------
+ Label miss;
+
+ __ IncrementCounter(&Counters::named_load_global_inline, 1);
+
+ // Get the receiver from the stack.
+ __ movq(rax, (Operand(rsp, kPointerSize)));
+
+ // If the object is the holder then we know that it's a global
+ // object which can only happen for contextual loads. In this case,
+ // the receiver cannot be a smi.
+ if (object != holder) {
+ __ testl(rax, Immediate(kSmiTagMask));
+ __ j(zero, &miss);
+ }
+
+ // Check that the maps haven't changed.
+ CheckPrototypes(object, rax, holder, rbx, rdx, name, &miss);
+
+ // Get the value from the cell.
+ __ Move(rax, Handle<JSGlobalPropertyCell>(cell));
+ __ movq(rax, FieldOperand(rax, JSGlobalPropertyCell::kValueOffset));
+
+ // Check for deleted property if property can actually be deleted.
+ if (!is_dont_delete) {
+ __ Cmp(rax, Factory::the_hole_value());
+ __ j(equal, &miss);
+ } else if (FLAG_debug_code) {
+ __ Cmp(rax, Factory::the_hole_value());
+ __ Check(not_equal, "DontDelete cells can't contain the hole");
+ }
+
+ __ ret(0);
+
+ __ bind(&miss);
+ __ DecrementCounter(&Counters::named_load_global_inline, 1);
+ __ IncrementCounter(&Counters::named_load_global_inline_miss, 1);
+ GenerateLoadMiss(masm(), Code::LOAD_IC);
+
+ // Return the generated code.
+ return GetCode(NORMAL, name);
}
@@ -129,12 +427,38 @@ Object* StoreStubCompiler::CompileStoreCallback(JSObject* a,
}
-Object* StoreStubCompiler::CompileStoreField(JSObject* a,
- int b,
- Map* c,
- String* d) {
- UNIMPLEMENTED();
- return NULL;
+Object* StoreStubCompiler::CompileStoreField(JSObject* object,
+ int index,
+ Map* transition,
+ String* name) {
+ // ----------- S t a t e -------------
+ // -- rax : value
+ // -- rcx : name
+ // -- rsp[0] : return address
+ // -- rsp[8] : receiver
+ // -----------------------------------
+ Label miss;
+
+ // Get the object from the stack.
+ __ movq(rbx, Operand(rsp, 1 * kPointerSize));
+
+ // Generate store field code. Trashes the name register.
+ GenerateStoreField(masm(),
+ Builtins::StoreIC_ExtendStorage,
+ object,
+ index,
+ transition,
+ rbx, rcx, rdx,
+ &miss);
+
+ // Handle store cache miss.
+ __ bind(&miss);
+ __ Move(rcx, Handle<String>(name)); // restore name
+ Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
+ __ Jump(ic, RelocInfo::CODE_TARGET);
+
+ // Return the generated code.
+ return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
}
@@ -175,6 +499,308 @@ Object* StubCompiler::CompileLazyCompile(Code::Flags flags) {
return GetCodeWithFlags(flags, "LazyCompileStub");
}
+
+Register StubCompiler::CheckPrototypes(JSObject* object,
+ Register object_reg,
+ JSObject* holder,
+ Register holder_reg,
+ Register scratch,
+ String* name,
+ Label* miss) {
+ // Check that the maps haven't changed.
+ Register result =
+ __ CheckMaps(object, object_reg, holder, holder_reg, scratch, miss);
+
+ // If we've skipped any global objects, it's not enough to verify
+ // that their maps haven't changed.
+ while (object != holder) {
+ if (object->IsGlobalObject()) {
+ GlobalObject* global = GlobalObject::cast(object);
+ Object* probe = global->EnsurePropertyCell(name);
+ if (probe->IsFailure()) {
+ set_failure(Failure::cast(probe));
+ return result;
+ }
+ JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
+ ASSERT(cell->value()->IsTheHole());
+ __ Move(scratch, Handle<Object>(cell));
+ __ Cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
+ Factory::the_hole_value());
+ __ j(not_equal, miss);
+ }
+ object = JSObject::cast(object->GetPrototype());
+ }
+
+ // Return the register containing the holder.
+ return result;
+}
+
+
+void StubCompiler::GenerateLoadField(JSObject* object,
+ JSObject* holder,
+ Register receiver,
+ Register scratch1,
+ Register scratch2,
+ int index,
+ String* name,
+ Label* miss) {
+ // Check that the receiver isn't a smi.
+ __ testl(receiver, Immediate(kSmiTagMask));
+ __ j(zero, miss);
+
+ // Check the prototype chain.
+ Register reg =
+ CheckPrototypes(object, receiver, holder,
+ scratch1, scratch2, name, miss);
+
+ // Get the value from the properties.
+ GenerateFastPropertyLoad(masm(), rax, reg, holder, index);
+ __ ret(0);
+}
+
+
+void StubCompiler::GenerateLoadConstant(JSObject* object,
+ JSObject* holder,
+ Register receiver,
+ Register scratch1,
+ Register scratch2,
+ Object* value,
+ String* name,
+ Label* miss) {
+ // Check that the receiver isn't a smi.
+ __ testl(receiver, Immediate(kSmiTagMask));
+ __ j(zero, miss);
+
+ // Check that the maps haven't changed.
+ Register reg =
+ CheckPrototypes(object, receiver, holder,
+ scratch1, scratch2, name, miss);
+
+ // Return the constant value.
+ __ Move(rax, Handle<Object>(value));
+ __ ret(0);
+}
+
+
+#undef __
+
+//-----------------------------------------------------------------------------
+// StubCompiler static helper functions
+
+#define __ ACCESS_MASM(masm)
+
+
+static void ProbeTable(MacroAssembler* masm,
+ Code::Flags flags,
+ StubCache::Table table,
+ Register name,
+ Register offset) {
+ ExternalReference key_offset(SCTableReference::keyReference(table));
+ Label miss;
+
+ __ movq(kScratchRegister, key_offset);
+ // Check that the key in the entry matches the name.
+ __ cmpl(name, Operand(kScratchRegister, offset, times_4, 0));
+ __ j(not_equal, &miss);
+ // Get the code entry from the cache.
+ // Use key_offset + kPointerSize, rather than loading value_offset.
+ __ movq(kScratchRegister,
+ Operand(kScratchRegister, offset, times_4, kPointerSize));
+ // Check that the flags match what we're looking for.
+ __ movl(offset, FieldOperand(kScratchRegister, Code::kFlagsOffset));
+ __ and_(offset, Immediate(~Code::kFlagsNotUsedInLookup));
+ __ cmpl(offset, Immediate(flags));
+ __ j(not_equal, &miss);
+
+ // Jump to the first instruction in the code stub.
+ __ addq(kScratchRegister, Immediate(Code::kHeaderSize - kHeapObjectTag));
+ __ jmp(kScratchRegister);
+
+ __ bind(&miss);
+}
+
+
+void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
+ ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
+ Code* code = NULL;
+ if (kind == Code::LOAD_IC) {
+ code = Builtins::builtin(Builtins::LoadIC_Miss);
+ } else {
+ code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
+ }
+
+ Handle<Code> ic(code);
+ __ Jump(ic, RelocInfo::CODE_TARGET);
+}
+
+
+void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
+ int index,
+ Register prototype) {
+ // Load the global or builtins object from the current context.
+ __ movq(prototype,
+ Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
+ // Load the global context from the global or builtins object.
+ __ movq(prototype,
+ FieldOperand(prototype, GlobalObject::kGlobalContextOffset));
+ // Load the function from the global context.
+ __ movq(prototype, Operand(prototype, Context::SlotOffset(index)));
+ // Load the initial map. The global functions all have initial maps.
+ __ movq(prototype,
+ FieldOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
+ // Load the prototype from the initial map.
+ __ movq(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
+}
+
+
+// Load a fast property out of a holder object (src). In-object properties
+// are loaded directly otherwise the property is loaded from the properties
+// fixed array.
+void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
+ Register dst, Register src,
+ JSObject* holder, int index) {
+ // Adjust for the number of properties stored in the holder.
+ index -= holder->map()->inobject_properties();
+ if (index < 0) {
+ // Get the property straight out of the holder.
+ int offset = holder->map()->instance_size() + (index * kPointerSize);
+ __ movq(dst, FieldOperand(src, offset));
+ } else {
+ // Calculate the offset into the properties array.
+ int offset = index * kPointerSize + FixedArray::kHeaderSize;
+ __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset));
+ __ movq(dst, FieldOperand(dst, offset));
+ }
+}
+
+
+void StubCache::GenerateProbe(MacroAssembler* masm,
+ Code::Flags flags,
+ Register receiver,
+ Register name,
+ Register scratch,
+ Register extra) {
+ Label miss;
+ USE(extra); // The register extra is not used on the X64 platform.
+ // Make sure that code is valid. The shifting code relies on the
+ // entry size being 16.
+ ASSERT(sizeof(Entry) == 16);
+
+ // Make sure the flags do not name a specific type.
+ ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
+
+ // Make sure that there are no register conflicts.
+ ASSERT(!scratch.is(receiver));
+ ASSERT(!scratch.is(name));
+
+ // Check that the receiver isn't a smi.
+ __ testl(receiver, Immediate(kSmiTagMask));
+ __ j(zero, &miss);
+
+ // Get the map of the receiver and compute the hash.
+ __ movl(scratch, FieldOperand(name, String::kLengthOffset));
+ // Use only the low 32 bits of the map pointer.
+ __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
+ __ xor_(scratch, Immediate(flags));
+ __ and_(scratch, Immediate((kPrimaryTableSize - 1) << kHeapObjectTagSize));
+
+ // Probe the primary table.
+ ProbeTable(masm, flags, kPrimary, name, scratch);
+
+ // Primary miss: Compute hash for secondary probe.
+ __ movl(scratch, FieldOperand(name, String::kLengthOffset));
+ __ addl(scratch, FieldOperand(receiver, HeapObject::kMapOffset));
+ __ xor_(scratch, Immediate(flags));
+ __ and_(scratch, Immediate((kPrimaryTableSize - 1) << kHeapObjectTagSize));
+ __ subl(scratch, name);
+ __ addl(scratch, Immediate(flags));
+ __ and_(scratch, Immediate((kSecondaryTableSize - 1) << kHeapObjectTagSize));
+
+ // Probe the secondary table.
+ ProbeTable(masm, flags, kSecondary, name, scratch);
+
+ // Cache miss: Fall-through and let caller handle the miss by
+ // entering the runtime system.
+ __ bind(&miss);
+}
+
+
+void StubCompiler::GenerateStoreField(MacroAssembler* masm,
+ Builtins::Name storage_extend,
+ JSObject* object,
+ int index,
+ Map* transition,
+ Register receiver_reg,
+ Register name_reg,
+ Register scratch,
+ Label* miss_label) {
+ // Check that the object isn't a smi.
+ __ testl(receiver_reg, Immediate(kSmiTagMask));
+ __ j(zero, miss_label);
+
+ // Check that the map of the object hasn't changed.
+ __ Cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset),
+ Handle<Map>(object->map()));
+ __ j(not_equal, miss_label);
+
+ // Perform global security token check if needed.
+ if (object->IsJSGlobalProxy()) {
+ __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
+ }
+
+ // Stub never generated for non-global objects that require access
+ // checks.
+ ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+
+ // Perform map transition for the receiver if necessary.
+ if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
+ // The properties must be extended before we can store the value.
+ // We jump to a runtime call that extends the properties array.
+ __ Move(rcx, Handle<Map>(transition));
+ Handle<Code> ic(Builtins::builtin(storage_extend));
+ __ Jump(ic, RelocInfo::CODE_TARGET);
+ return;
+ }
+
+ if (transition != NULL) {
+ // Update the map of the object; no write barrier updating is
+ // needed because the map is never in new space.
+ __ Move(FieldOperand(receiver_reg, HeapObject::kMapOffset),
+ Handle<Map>(transition));
+ }
+
+ // Adjust for the number of properties stored in the object. Even in the
+ // face of a transition we can use the old map here because the size of the
+ // object and the number of in-object properties is not going to change.
+ index -= object->map()->inobject_properties();
+
+ if (index < 0) {
+ // Set the property straight into the object.
+ int offset = object->map()->instance_size() + (index * kPointerSize);
+ __ movq(FieldOperand(receiver_reg, offset), rax);
+
+ // Update the write barrier for the array address.
+ // Pass the value being stored in the now unused name_reg.
+ __ movq(name_reg, rax);
+ __ RecordWrite(receiver_reg, offset, name_reg, scratch);
+ } else {
+ // Write to the properties array.
+ int offset = index * kPointerSize + FixedArray::kHeaderSize;
+ // Get the properties array (optimistically).
+ __ movq(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
+ __ movq(FieldOperand(scratch, offset), rax);
+
+ // Update the write barrier for the array address.
+ // Pass the value being stored in the now unused name_reg.
+ __ movq(name_reg, rax);
+ __ RecordWrite(scratch, offset, name_reg, receiver_reg);
+ }
+
+ // Return the value (register rax).
+ __ ret(0);
+}
+
+
#undef __
diff --git a/V8Binding/v8/src/zone.cc b/V8Binding/v8/src/zone.cc
index d78c19b..33fe557 100644
--- a/V8Binding/v8/src/zone.cc
+++ b/V8Binding/v8/src/zone.cc
@@ -176,7 +176,10 @@ Address Zone::NewExpand(int size) {
new_size = Max(kSegmentOverhead + size, kMaximumSegmentSize);
}
Segment* segment = Segment::New(new_size);
- if (segment == NULL) V8::FatalProcessOutOfMemory("Zone");
+ if (segment == NULL) {
+ V8::FatalProcessOutOfMemory("Zone");
+ return NULL;
+ }
// Recompute 'top' and 'limit' based on the new segment.
Address result = RoundUp(segment->start(), kAlignment);
diff --git a/V8Binding/v8/test/cctest/cctest.status b/V8Binding/v8/test/cctest/cctest.status
index bb82fc8..b234ca3 100644
--- a/V8Binding/v8/test/cctest/cctest.status
+++ b/V8Binding/v8/test/cctest/cctest.status
@@ -63,7 +63,7 @@ test-api/TryCatchInTryFinally: FAIL
[ $arch == x64 ]
-test-regexp/Graph: CRASH || FAIL
+test-regexp/Graph: PASS || CRASH || FAIL
test-decls/Present: CRASH || FAIL
test-decls/Unknown: CRASH || FAIL
test-decls/Appearing: CRASH || FAIL
@@ -108,11 +108,9 @@ test-debug/StepWithException: CRASH || FAIL
test-debug/DebugBreak: CRASH || FAIL
test-debug/DisableBreak: CRASH || FAIL
test-debug/MessageQueues: CRASH || FAIL
-test-debug/CallFunctionInDebugger: CRASH || FAIL
+test-debug/CallFunctionInDebugger: SKIP
test-debug/RecursiveBreakpoints: CRASH || FAIL
test-debug/DebuggerUnload: CRASH || FAIL
-test-debug/DebuggerClearMessageHandler: CRASH || FAIL
-test-debug/DebuggerClearMessageHandlerWhileActive: CRASH || FAIL
test-debug/DebuggerHostDispatch: CRASH || FAIL
test-debug/DebugBreakInMessageHandler: CRASH || FAIL
test-api/HugeConsStringOutOfMemory: CRASH || FAIL
@@ -120,5 +118,5 @@ test-api/OutOfMemory: CRASH || FAIL
test-api/OutOfMemoryNested: CRASH || FAIL
test-api/Threading: CRASH || FAIL
test-api/TryCatchSourceInfo: CRASH || FAIL
-test-api/RegExpInterruption: CRASH || FAIL
-test-api/RegExpStringModification: CRASH || FAIL
+test-api/RegExpInterruption: PASS || TIMEOUT
+test-api/RegExpStringModification: PASS || TIMEOUT
diff --git a/V8Binding/v8/test/cctest/test-api.cc b/V8Binding/v8/test/cctest/test-api.cc
index 5b04b2c..806e711 100644
--- a/V8Binding/v8/test/cctest/test-api.cc
+++ b/V8Binding/v8/test/cctest/test-api.cc
@@ -1266,6 +1266,38 @@ THREADED_TEST(InternalFields) {
}
+THREADED_TEST(InternalFieldsNativePointers) {
+ v8::HandleScope scope;
+ LocalContext env;
+
+ Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
+ Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
+ instance_templ->SetInternalFieldCount(1);
+ Local<v8::Object> obj = templ->GetFunction()->NewInstance();
+ CHECK_EQ(1, obj->InternalFieldCount());
+ CHECK(obj->GetPointerFromInternalField(0) == NULL);
+
+ char* data = new char[100];
+
+ void* aligned = data;
+ CHECK_EQ(0, reinterpret_cast<uintptr_t>(aligned) & 0x1);
+ void* unaligned = data + 1;
+ CHECK_EQ(1, reinterpret_cast<uintptr_t>(unaligned) & 0x1);
+
+ // Check reading and writing aligned pointers.
+ obj->SetPointerInInternalField(0, aligned);
+ i::Heap::CollectAllGarbage();
+ CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
+
+ // Check reading and writing unaligned pointers.
+ obj->SetPointerInInternalField(0, unaligned);
+ i::Heap::CollectAllGarbage();
+ CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
+
+ delete[] data;
+}
+
+
THREADED_TEST(IdentityHash) {
v8::HandleScope scope;
LocalContext env;
@@ -5024,6 +5056,236 @@ THREADED_TEST(InterceptorLoadICWithOverride) {
}
+// Test the case when we stored field into
+// a stub, but interceptor produced value on its own.
+THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
+ CheckInterceptorLoadIC(InterceptorLoadXICGetter,
+ "proto = new Object();"
+ "o.__proto__ = proto;"
+ "proto.x = 239;"
+ "for (var i = 0; i < 1000; i++) {"
+ " o.x;"
+ // Now it should be ICed and keep a reference to x defined on proto
+ "}"
+ "var result = 0;"
+ "for (var i = 0; i < 1000; i++) {"
+ " result += o.x;"
+ "}"
+ "result;",
+ 42 * 1000);
+}
+
+
+// Test the case when we stored field into
+// a stub, but it got invalidated later on.
+THREADED_TEST(InterceptorLoadICInvalidatedField) {
+ CheckInterceptorLoadIC(InterceptorLoadXICGetter,
+ "proto1 = new Object();"
+ "proto2 = new Object();"
+ "o.__proto__ = proto1;"
+ "proto1.__proto__ = proto2;"
+ "proto2.y = 239;"
+ "for (var i = 0; i < 1000; i++) {"
+ " o.y;"
+ // Now it should be ICed and keep a reference to y defined on proto2
+ "}"
+ "proto1.y = 42;"
+ "var result = 0;"
+ "for (var i = 0; i < 1000; i++) {"
+ " result += o.y;"
+ "}"
+ "result;",
+ 42 * 1000);
+}
+
+
+// Test the case when we stored field into
+// a stub, but it got invalidated later on due to override on
+// global object which is between interceptor and fields' holders.
+THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
+ CheckInterceptorLoadIC(InterceptorLoadXICGetter,
+ "o.__proto__ = this;" // set a global to be a proto of o.
+ "this.__proto__.y = 239;"
+ "for (var i = 0; i < 10; i++) {"
+ " if (o.y != 239) throw 'oops: ' + o.y;"
+ // Now it should be ICed and keep a reference to y defined on field_holder.
+ "}"
+ "this.y = 42;" // Assign on a global.
+ "var result = 0;"
+ "for (var i = 0; i < 10; i++) {"
+ " result += o.y;"
+ "}"
+ "result;",
+ 42 * 10);
+}
+
+
+static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) {
+ ApiTestFuzzer::Fuzz();
+ return v8_num(239);
+}
+
+
+static void SetOnThis(Local<String> name,
+ Local<Value> value,
+ const AccessorInfo& info) {
+ info.This()->ForceSet(name, value);
+}
+
+
+THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+ templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+ templ->SetAccessor(v8_str("y"), Return239);
+ LocalContext context;
+ context->Global()->Set(v8_str("o"), templ->NewInstance());
+ v8::Handle<Value> value = CompileRun(
+ "var result = 0;"
+ "for (var i = 0; i < 7; i++) {"
+ " result = o.y;"
+ "}");
+ CHECK_EQ(239, value->Int32Value());
+}
+
+
+THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
+ templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+ v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
+ templ_p->SetAccessor(v8_str("y"), Return239);
+
+ LocalContext context;
+ context->Global()->Set(v8_str("o"), templ_o->NewInstance());
+ context->Global()->Set(v8_str("p"), templ_p->NewInstance());
+
+ v8::Handle<Value> value = CompileRun(
+ "o.__proto__ = p;"
+ "var result = 0;"
+ "for (var i = 0; i < 7; i++) {"
+ " result = o.x + o.y;"
+ "}");
+ CHECK_EQ(239 + 42, value->Int32Value());
+}
+
+
+THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+ templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+ templ->SetAccessor(v8_str("y"), Return239);
+
+ LocalContext context;
+ context->Global()->Set(v8_str("o"), templ->NewInstance());
+
+ v8::Handle<Value> value = CompileRun(
+ "fst = new Object(); fst.__proto__ = o;"
+ "snd = new Object(); snd.__proto__ = fst;"
+ "var result1 = 0;"
+ "for (var i = 0; i < 7; i++) {"
+ " result1 = snd.x;"
+ "}"
+ "fst.x = 239;"
+ "var result = 0;"
+ "for (var i = 0; i < 7; i++) {"
+ " result = snd.x;"
+ "}"
+ "result + result1");
+ CHECK_EQ(239 + 42, value->Int32Value());
+}
+
+
+// Test the case when we stored callback into
+// a stub, but interceptor produced value on its own.
+THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
+ templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+ v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
+ templ_p->SetAccessor(v8_str("y"), Return239);
+
+ LocalContext context;
+ context->Global()->Set(v8_str("o"), templ_o->NewInstance());
+ context->Global()->Set(v8_str("p"), templ_p->NewInstance());
+
+ v8::Handle<Value> value = CompileRun(
+ "o.__proto__ = p;"
+ "for (var i = 0; i < 7; i++) {"
+ " o.x;"
+ // Now it should be ICed and keep a reference to x defined on p
+ "}"
+ "var result = 0;"
+ "for (var i = 0; i < 7; i++) {"
+ " result += o.x;"
+ "}"
+ "result");
+ CHECK_EQ(42 * 7, value->Int32Value());
+}
+
+
+// Test the case when we stored callback into
+// a stub, but it got invalidated later on.
+THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
+ templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+ v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
+ templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
+
+ LocalContext context;
+ context->Global()->Set(v8_str("o"), templ_o->NewInstance());
+ context->Global()->Set(v8_str("p"), templ_p->NewInstance());
+
+ v8::Handle<Value> value = CompileRun(
+ "inbetween = new Object();"
+ "o.__proto__ = inbetween;"
+ "inbetween.__proto__ = p;"
+ "for (var i = 0; i < 10; i++) {"
+ " o.y;"
+ // Now it should be ICed and keep a reference to y defined on p
+ "}"
+ "inbetween.y = 42;"
+ "var result = 0;"
+ "for (var i = 0; i < 10; i++) {"
+ " result += o.y;"
+ "}"
+ "result");
+ CHECK_EQ(42 * 10, value->Int32Value());
+}
+
+
+// Test the case when we stored callback into
+// a stub, but it got invalidated later on due to override on
+// global object which is between interceptor and callbacks' holders.
+THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
+ templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+ v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
+ templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis);
+
+ LocalContext context;
+ context->Global()->Set(v8_str("o"), templ_o->NewInstance());
+ context->Global()->Set(v8_str("p"), templ_p->NewInstance());
+
+ v8::Handle<Value> value = CompileRun(
+ "o.__proto__ = this;"
+ "this.__proto__ = p;"
+ "for (var i = 0; i < 10; i++) {"
+ " if (o.y != 239) throw 'oops: ' + o.y;"
+ // Now it should be ICed and keep a reference to y defined on p
+ "}"
+ "this.y = 42;"
+ "var result = 0;"
+ "for (var i = 0; i < 10; i++) {"
+ " result += o.y;"
+ "}"
+ "result");
+ CHECK_EQ(42 * 10, value->Int32Value());
+}
+
+
static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name,
const AccessorInfo& info) {
ApiTestFuzzer::Fuzz();
@@ -5108,6 +5370,192 @@ THREADED_TEST(InterceptorCallIC) {
CHECK_EQ(42, value->Int32Value());
}
+
+// This test checks that if interceptor doesn't provide
+// a value, we can fetch regular value.
+THREADED_TEST(InterceptorCallICSeesOthers) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+ templ->SetNamedPropertyHandler(NoBlockGetterX);
+ LocalContext context;
+ context->Global()->Set(v8_str("o"), templ->NewInstance());
+ v8::Handle<Value> value = CompileRun(
+ "o.x = function f(x) { return x + 1; };"
+ "var result = 0;"
+ "for (var i = 0; i < 7; i++) {"
+ " result = o.x(41);"
+ "}");
+ CHECK_EQ(42, value->Int32Value());
+}
+
+
+static v8::Handle<Value> call_ic_function4;
+static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name,
+ const AccessorInfo& info) {
+ ApiTestFuzzer::Fuzz();
+ CHECK(v8_str("x")->Equals(name));
+ return call_ic_function4;
+}
+
+
+// This test checks that if interceptor provides a function,
+// even if we cached shadowed variant, interceptor's function
+// is invoked
+THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+ templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
+ LocalContext context;
+ context->Global()->Set(v8_str("o"), templ->NewInstance());
+ call_ic_function4 =
+ v8_compile("function f(x) { return x - 1; }; f")->Run();
+ v8::Handle<Value> value = CompileRun(
+ "o.__proto__.x = function(x) { return x + 1; };"
+ "var result = 0;"
+ "for (var i = 0; i < 1000; i++) {"
+ " result = o.x(42);"
+ "}");
+ CHECK_EQ(41, value->Int32Value());
+}
+
+
+// Test the case when we stored cacheable lookup into
+// a stub, but it got invalidated later on
+THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+ templ->SetNamedPropertyHandler(NoBlockGetterX);
+ LocalContext context;
+ context->Global()->Set(v8_str("o"), templ->NewInstance());
+ v8::Handle<Value> value = CompileRun(
+ "proto1 = new Object();"
+ "proto2 = new Object();"
+ "o.__proto__ = proto1;"
+ "proto1.__proto__ = proto2;"
+ "proto2.y = function(x) { return x + 1; };"
+ // Invoke it many times to compile a stub
+ "for (var i = 0; i < 7; i++) {"
+ " o.y(42);"
+ "}"
+ "proto1.y = function(x) { return x - 1; };"
+ "var result = 0;"
+ "for (var i = 0; i < 7; i++) {"
+ " result += o.y(42);"
+ "}");
+ CHECK_EQ(41 * 7, value->Int32Value());
+}
+
+
+static v8::Handle<Value> call_ic_function5;
+static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name,
+ const AccessorInfo& info) {
+ ApiTestFuzzer::Fuzz();
+ if (v8_str("x")->Equals(name))
+ return call_ic_function5;
+ else
+ return Local<Value>();
+}
+
+
+// This test checks that if interceptor doesn't provide a function,
+// cached constant function is used
+THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+ templ->SetNamedPropertyHandler(NoBlockGetterX);
+ LocalContext context;
+ context->Global()->Set(v8_str("o"), templ->NewInstance());
+ v8::Handle<Value> value = CompileRun(
+ "function inc(x) { return x + 1; };"
+ "inc(1);"
+ "o.x = inc;"
+ "var result = 0;"
+ "for (var i = 0; i < 1000; i++) {"
+ " result = o.x(42);"
+ "}");
+ CHECK_EQ(43, value->Int32Value());
+}
+
+
+// This test checks that if interceptor provides a function,
+// even if we cached constant function, interceptor's function
+// is invoked
+THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+ templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
+ LocalContext context;
+ context->Global()->Set(v8_str("o"), templ->NewInstance());
+ call_ic_function5 =
+ v8_compile("function f(x) { return x - 1; }; f")->Run();
+ v8::Handle<Value> value = CompileRun(
+ "function inc(x) { return x + 1; };"
+ "inc(1);"
+ "o.x = inc;"
+ "var result = 0;"
+ "for (var i = 0; i < 1000; i++) {"
+ " result = o.x(42);"
+ "}");
+ CHECK_EQ(41, value->Int32Value());
+}
+
+
+// Test the case when we stored constant function into
+// a stub, but it got invalidated later on
+THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+ templ->SetNamedPropertyHandler(NoBlockGetterX);
+ LocalContext context;
+ context->Global()->Set(v8_str("o"), templ->NewInstance());
+ v8::Handle<Value> value = CompileRun(
+ "function inc(x) { return x + 1; };"
+ "inc(1);"
+ "proto1 = new Object();"
+ "proto2 = new Object();"
+ "o.__proto__ = proto1;"
+ "proto1.__proto__ = proto2;"
+ "proto2.y = inc;"
+ // Invoke it many times to compile a stub
+ "for (var i = 0; i < 7; i++) {"
+ " o.y(42);"
+ "}"
+ "proto1.y = function(x) { return x - 1; };"
+ "var result = 0;"
+ "for (var i = 0; i < 7; i++) {"
+ " result += o.y(42);"
+ "}");
+ CHECK_EQ(41 * 7, value->Int32Value());
+}
+
+
+// Test the case when we stored constant function into
+// a stub, but it got invalidated later on due to override on
+// global object which is between interceptor and constant function' holders.
+THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+ templ->SetNamedPropertyHandler(NoBlockGetterX);
+ LocalContext context;
+ context->Global()->Set(v8_str("o"), templ->NewInstance());
+ v8::Handle<Value> value = CompileRun(
+ "function inc(x) { return x + 1; };"
+ "inc(1);"
+ "o.__proto__ = this;"
+ "this.__proto__.y = inc;"
+ // Invoke it many times to compile a stub
+ "for (var i = 0; i < 7; i++) {"
+ " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
+ "}"
+ "this.y = function(x) { return x - 1; };"
+ "var result = 0;"
+ "for (var i = 0; i < 7; i++) {"
+ " result += o.y(42);"
+ "}");
+ CHECK_EQ(41 * 7, value->Int32Value());
+}
+
+
static int interceptor_call_count = 0;
static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
@@ -5768,6 +6216,7 @@ THREADED_TEST(NestedHandleScopeAndContexts) {
THREADED_TEST(ExternalAllocatedMemory) {
v8::HandleScope outer;
+ v8::Persistent<Context> env = Context::New();
const int kSize = 1024*1024;
CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize);
CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0);
@@ -7081,3 +7530,21 @@ THREADED_TEST(ReplaceConstantFunction) {
obj_clone->Set(foo_string, v8::String::New("Hello"));
CHECK(!obj->Get(foo_string)->IsUndefined());
}
+
+
+// Regression test for http://crbug.com/16276.
+THREADED_TEST(Regress16276) {
+ v8::HandleScope scope;
+ LocalContext context;
+ // Force the IC in f to be a dictionary load IC.
+ CompileRun("function f(obj) { return obj.x; }\n"
+ "var obj = { x: { foo: 42 }, y: 87 };\n"
+ "var x = obj.x;\n"
+ "delete obj.y;\n"
+ "for (var i = 0; i < 5; i++) f(obj);");
+ // Detach the global object to make 'this' refer directly to the
+ // global object (not the proxy), and make sure that the dictionary
+ // load IC doesn't mess up loading directly from the global object.
+ context->DetachGlobal();
+ CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
+}
diff --git a/V8Binding/v8/test/cctest/test-heap.cc b/V8Binding/v8/test/cctest/test-heap.cc
index 396bcc5..5163ff9 100644
--- a/V8Binding/v8/test/cctest/test-heap.cc
+++ b/V8Binding/v8/test/cctest/test-heap.cc
@@ -36,7 +36,7 @@ TEST(HeapMaps) {
InitializeVM();
CheckMap(Heap::meta_map(), MAP_TYPE, Map::kSize);
CheckMap(Heap::heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
- CheckMap(Heap::fixed_array_map(), FIXED_ARRAY_TYPE, Array::kAlignedSize);
+ CheckMap(Heap::fixed_array_map(), FIXED_ARRAY_TYPE, FixedArray::kHeaderSize);
CheckMap(Heap::long_string_map(), LONG_STRING_TYPE,
SeqTwoByteString::kAlignedSize);
}
diff --git a/V8Binding/v8/test/cctest/test-mark-compact.cc b/V8Binding/v8/test/cctest/test-mark-compact.cc
index 8db7339..743375d 100644
--- a/V8Binding/v8/test/cctest/test-mark-compact.cc
+++ b/V8Binding/v8/test/cctest/test-mark-compact.cc
@@ -86,7 +86,8 @@ TEST(Promotion) {
v8::HandleScope sc;
// Allocate a fixed array in the new space.
- int array_size = (Heap::MaxObjectSizeInPagedSpace() - Array::kHeaderSize) /
+ int array_size =
+ (Heap::MaxObjectSizeInPagedSpace() - FixedArray::kHeaderSize) /
(kPointerSize * 4);
Object* obj = Heap::AllocateFixedArray(array_size);
CHECK(!obj->IsFailure());
@@ -118,7 +119,7 @@ TEST(NoPromotion) {
CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
// Allocate a big Fixed array in the new space.
- int size = (Heap::MaxObjectSizeInPagedSpace() - Array::kHeaderSize) /
+ int size = (Heap::MaxObjectSizeInPagedSpace() - FixedArray::kHeaderSize) /
kPointerSize;
Object* obj = Heap::AllocateFixedArray(size);
diff --git a/V8Binding/v8/test/message/message.status b/V8Binding/v8/test/message/message.status
index d40151e..9afaa0f 100644
--- a/V8Binding/v8/test/message/message.status
+++ b/V8Binding/v8/test/message/message.status
@@ -32,13 +32,13 @@ bugs: FAIL
[ $arch == x64 ]
-simple-throw.js: FAIL
-try-catch-finally-throw-in-catch-and-finally.js: FAIL
-try-catch-finally-throw-in-catch.js: FAIL
-try-catch-finally-throw-in-finally.js: FAIL
-try-finally-throw-in-finally.js: FAIL
-try-finally-throw-in-try-and-finally.js: FAIL
-try-finally-throw-in-try.js: FAIL
-overwritten-builtins.js: FAIL
-regress-73.js: FAIL
-regress-75.js: FAIL
+simple-throw: FAIL
+try-catch-finally-throw-in-catch-and-finally: FAIL
+try-catch-finally-throw-in-catch: FAIL
+try-catch-finally-throw-in-finally: FAIL
+try-finally-throw-in-finally: FAIL
+try-finally-throw-in-try-and-finally: FAIL
+try-finally-throw-in-try: FAIL
+overwritten-builtins: FAIL
+regress/regress-73: FAIL
+regress/regress-75: FAIL
diff --git a/V8Binding/v8/test/mjsunit/debug-stepin-accessor.js b/V8Binding/v8/test/mjsunit/debug-stepin-accessor.js
new file mode 100644
index 0000000..8b24c3c
--- /dev/null
+++ b/V8Binding/v8/test/mjsunit/debug-stepin-accessor.js
@@ -0,0 +1,248 @@
+// 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.
+
+// Flags: --expose-debug-as debug
+
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+var exception = null;
+var state = 1;
+var expected_source_line_text = null;
+var expected_function_name = null;
+
+// Simple debug event handler which first time will cause 'step in' action
+// to get into g.call and than check that execution is pauesed inside
+// function 'g'.
+function listener(event, exec_state, event_data, data) {
+ try {
+ if (event == Debug.DebugEvent.Break) {
+ if (state == 1) {
+ exec_state.prepareStep(Debug.StepAction.StepIn, 2);
+ state = 2;
+ } else if (state == 2) {
+ assertEquals(expected_source_line_text,
+ event_data.sourceLineText());
+ assertEquals(expected_function_name, event_data.func().name());
+ state = 3;
+ }
+ }
+ } catch(e) {
+ exception = e;
+ }
+};
+
+// Add the debug event listener.
+Debug.setListener(listener);
+
+
+var c = {
+ name: 'name ',
+ get getter1() {
+ return this.name; // getter 1
+ },
+ get getter2() {
+ return { // getter 2
+ 'a': c.name
+ };
+ },
+ set setter1(n) {
+ this.name = n; // setter 1
+ }
+};
+
+c.__defineGetter__('y', function getterY() {
+ return this.name; // getter y
+});
+
+c.__defineGetter__(3, function getter3() {
+ return this.name; // getter 3
+});
+
+c.__defineSetter__('y', function setterY(n) {
+ this.name = n; // setter y
+});
+
+c.__defineSetter__(3, function setter3(n) {
+ this.name = n; // setter 3
+});
+
+var d = {
+ 'c': c,
+};
+
+function testGetter1_1() {
+ expected_function_name = 'getter1';
+ expected_source_line_text = ' return this.name; // getter 1';
+ debugger;
+ var x = c.getter1;
+}
+
+function testGetter1_2() {
+ expected_function_name = 'getter1';
+ expected_source_line_text = ' return this.name; // getter 1';
+ debugger;
+ var x = c['getter1'];
+}
+
+function testGetter1_3() {
+ expected_function_name = 'getter1';
+ expected_source_line_text = ' return this.name; // getter 1';
+ debugger;
+ for (var i = 1; i < 2; i++) {
+ var x = c['getter' + i];
+ }
+}
+
+function testGetter1_4() {
+ expected_function_name = 'getter1';
+ expected_source_line_text = ' return this.name; // getter 1';
+ debugger;
+ var x = d.c.getter1;
+}
+
+function testGetter1_5() {
+ expected_function_name = 'getter1';
+ expected_source_line_text = ' return this.name; // getter 1';
+ for (var i = 2; i != 1; i--);
+ debugger;
+ var x = d.c['getter' + i];
+}
+
+function testGetter2_1() {
+ expected_function_name = 'getter2';
+ expected_source_line_text = ' return { // getter 2';
+ for (var i = 2; i != 1; i--);
+ debugger;
+ var t = d.c.getter2.name;
+}
+
+
+function testGetterY_1() {
+ expected_function_name = 'getterY';
+ expected_source_line_text = ' return this.name; // getter y';
+ debugger;
+ var t = d.c.y;
+}
+
+function testIndexedGetter3_1() {
+ expected_function_name = 'getter3';
+ expected_source_line_text = ' return this.name; // getter 3';
+ debugger;
+ var r = d.c[3];
+}
+
+function testSetterY_1() {
+ expected_function_name = 'setterY';
+ expected_source_line_text = ' this.name = n; // setter y';
+ debugger;
+ d.c.y = 'www';
+}
+
+function testIndexedSetter3_1() {
+ expected_function_name = 'setter3';
+ expected_source_line_text = ' this.name = n; // setter 3';
+ var i = 3
+ debugger;
+ d.c[3] = 'www';
+}
+
+function testSetter1_1() {
+ expected_function_name = 'setter1';
+ expected_source_line_text = ' this.name = n; // setter 1';
+ debugger;
+ d.c.setter1 = 'aa';
+}
+
+function testSetter1_2() {
+ expected_function_name = 'setter1';
+ expected_source_line_text = ' this.name = n; // setter 1';
+ debugger;
+ d.c['setter1'] = 'bb';
+}
+
+function testSetter1_3() {
+ expected_function_name = 'setter1';
+ expected_source_line_text = ' this.name = n; // setter 1';
+ for (var i = 2; i != 1; i--);
+ debugger;
+ d.c['setter' + i] = i;
+}
+
+var e = {
+ name: 'e'
+};
+e.__proto__ = c;
+
+function testProtoGetter1_1() {
+ expected_function_name = 'getter1';
+ expected_source_line_text = ' return this.name; // getter 1';
+ debugger;
+ var x = e.getter1;
+}
+
+function testProtoSetter1_1() {
+ expected_function_name = 'setter1';
+ expected_source_line_text = ' this.name = n; // setter 1';
+ debugger;
+ e.setter1 = 'aa';
+}
+
+function testProtoIndexedGetter3_1() {
+ expected_function_name = 'getter3';
+ expected_source_line_text = ' return this.name; // getter 3';
+ debugger;
+ var x = e[3];
+}
+
+function testProtoIndexedSetter3_1() {
+ expected_function_name = 'setter3';
+ expected_source_line_text = ' this.name = n; // setter 3';
+ debugger;
+ e[3] = 'new val';
+}
+
+function testProtoSetter1_2() {
+ expected_function_name = 'setter1';
+ expected_source_line_text = ' this.name = n; // setter 1';
+ for (var i = 2; i != 1; i--);
+ debugger;
+ e['setter' + i] = 'aa';
+}
+
+for (var n in this) {
+ if (n.substr(0, 4) != 'test') {
+ continue;
+ }
+ state = 1;
+ this[n]();
+ assertNull(exception);
+ assertEquals(3, state);
+}
+
+// Get rid of the debug event listener.
+Debug.setListener(null);
diff --git a/V8Binding/v8/test/mjsunit/mjsunit.status b/V8Binding/v8/test/mjsunit/mjsunit.status
index 962e4d3..d30e78c 100644
--- a/V8Binding/v8/test/mjsunit/mjsunit.status
+++ b/V8Binding/v8/test/mjsunit/mjsunit.status
@@ -58,6 +58,7 @@ debug-ignore-breakpoints: CRASH || FAIL
debug-multiple-breakpoints: CRASH || FAIL
debug-setbreakpoint: CRASH || FAIL || PASS
debug-step-stub-callfunction: SKIP
+debug-stepin-accessor: CRASH || FAIL
debug-stepin-constructor: CRASH, FAIL
debug-stepin-function-call: CRASH || FAIL
debug-step: SKIP
@@ -69,40 +70,44 @@ regress/regress-269: SKIP
# Fails on real ARM hardware but not on the simulator.
string-compare-alignment: PASS || FAIL
+# Times out often in release mode on ARM.
+array-splice: PASS || TIMEOUT
[ $arch == x64 ]
-debug-backtrace.js: CRASH || FAIL
-date-parse.js: CRASH || FAIL
-debug-backtrace-text.js: CRASH || FAIL
-debug-multiple-breakpoints.js: CRASH || FAIL
-debug-breakpoints.js: CRASH || FAIL
-debug-changebreakpoint.js: CRASH || FAIL
-debug-clearbreakpoint.js: CRASH || FAIL
-debug-conditional-breakpoints.js: CRASH || FAIL
-debug-constructor.js: CRASH || FAIL
-debug-continue.js: CRASH || FAIL
-debug-enable-disable-breakpoints.js: CRASH || FAIL
-debug-evaluate-recursive.js: CRASH || FAIL
-debug-event-listener.js: CRASH || FAIL
-debug-evaluate.js: CRASH || FAIL
-debug-ignore-breakpoints.js: CRASH || FAIL
-debug-setbreakpoint.js: CRASH || FAIL
-debug-step-stub-callfunction.js: CRASH || FAIL
-debug-step.js: CRASH || FAIL
-mirror-date.js: CRASH || FAIL
-invalid-lhs.js: CRASH || FAIL
-debug-stepin-constructor.js: CRASH || FAIL
-new.js: CRASH || FAIL
-fuzz-natives.js: CRASH || FAIL
-greedy.js: CRASH || FAIL
-debug-handle.js: CRASH || FAIL
-string-indexof.js: CRASH || FAIL
-debug-clearbreakpointgroup.js: CRASH || FAIL
-regress/regress-269.js: CRASH || FAIL
-div-mod.js: CRASH || FAIL
-unicode-test.js: CRASH || FAIL
-regress/regress-392.js: CRASH || FAIL
-regress/regress-1200351.js: CRASH || FAIL
-regress/regress-998565.js: CRASH || FAIL
-tools/tickprocessor.js: CRASH || FAIL
+debug-backtrace: CRASH || FAIL
+date-parse: CRASH || FAIL
+debug-backtrace-text: CRASH || FAIL
+debug-multiple-breakpoints: CRASH || FAIL
+debug-breakpoints: CRASH || FAIL
+debug-changebreakpoint: CRASH || FAIL
+debug-clearbreakpoint: CRASH || FAIL
+debug-conditional-breakpoints: CRASH || FAIL
+debug-constructor: CRASH || FAIL
+debug-continue: CRASH || FAIL
+debug-enable-disable-breakpoints: CRASH || FAIL
+debug-evaluate-recursive: CRASH || FAIL
+debug-event-listener: CRASH || FAIL
+debug-evaluate: CRASH || FAIL
+debug-ignore-breakpoints: CRASH || FAIL
+debug-setbreakpoint: CRASH || FAIL
+debug-step-stub-callfunction: CRASH || FAIL
+debug-step: CRASH || FAIL
+mirror-date: CRASH || FAIL
+invalid-lhs: PASS || CRASH || FAIL
+debug-stepin-constructor: CRASH || FAIL
+debug-stepin-function-call: CRASH || FAIL
+debug-stepin-accessor: CRASH || FAIL
+new: CRASH || FAIL
+fuzz-natives: PASS || TIMEOUT
+greedy: PASS || TIMEOUT
+debug-handle: CRASH || FAIL
+string-indexof: PASS || TIMEOUT
+debug-clearbreakpointgroup: CRASH || FAIL
+regress/regress-269: CRASH || FAIL
+div-mod: CRASH || FAIL
+unicode-test: PASS || TIMEOUT
+regress/regress-392: CRASH || FAIL
+regress/regress-1200351: CRASH || FAIL
+regress/regress-998565: CRASH || FAIL
+tools/tickprocessor: PASS || CRASH || FAIL
diff --git a/V8Binding/v8/test/mjsunit/regexp-call-as-function.js b/V8Binding/v8/test/mjsunit/regexp-call-as-function.js
new file mode 100644
index 0000000..4cbe7f9
--- /dev/null
+++ b/V8Binding/v8/test/mjsunit/regexp-call-as-function.js
@@ -0,0 +1,36 @@
+// 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.
+
+// Test that regular expressions can be called as functions. Calling
+// a regular expression as a function corresponds to calling it's exec
+// method.
+
+var regexp = /a(b)(c)/;
+var subject = "xyzabcde";
+var expected = 'abc,b,c';
+assertEquals(expected, String(regexp.exec(subject)));
+assertEquals(expected, String(regexp(subject)));
diff --git a/V8Binding/v8/test/mjsunit/regress/regress-155924.js b/V8Binding/v8/test/mjsunit/regress/regress-155924.js
new file mode 100644
index 0000000..666e3ba
--- /dev/null
+++ b/V8Binding/v8/test/mjsunit/regress/regress-155924.js
@@ -0,0 +1,46 @@
+// 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.
+
+// A HeapNumber with certain bits in the mantissa of the floating point
+// value should not be able to masquerade as a string in a keyed lookup
+// inline cache stub. See http://codereview.chromium.org/155924.
+
+A = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
+
+function foo() {
+ x = 1 << 26;
+ x = x * x;
+ // The following floating-point heap number has a second word similar
+ // to that of the string "5":
+ // 2^52 + index << cached_index_shift + cached_index_tag
+ x = x + (5 << 2) + (1 << 1);
+ return A[x];
+}
+
+assertEquals(undefined, foo(), "First lookup A[bad_float]");
+assertEquals(undefined, foo(), "Second lookup A[bad_float]");
+assertEquals(undefined, foo(), "Third lookup A[bad_float]");
diff --git a/V8Binding/v8/test/mjsunit/regress/regress-345.js b/V8Binding/v8/test/mjsunit/regress/regress-345.js
new file mode 100644
index 0000000..f7f28a1
--- /dev/null
+++ b/V8Binding/v8/test/mjsunit/regress/regress-345.js
@@ -0,0 +1,51 @@
+// 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.
+
+// Escaping to the same target from both the try and catch blocks of
+// try...catch...finally should not fail at compile-time.
+//
+// Reported by nth10sd.
+// See http://code.google.com/p/v8/issues/detail?id=345
+
+do {
+ try {
+ continue;
+ } catch (e) {
+ continue;
+ } finally {
+ }
+} while (false);
+
+
+L: {
+ try {
+ break L;
+ } catch (e) {
+ break L;
+ } finally {
+ }
+}
diff --git a/V8Binding/v8/test/mjsunit/regress/regress-406.js b/V8Binding/v8/test/mjsunit/regress/regress-406.js
new file mode 100644
index 0000000..f48a5de
--- /dev/null
+++ b/V8Binding/v8/test/mjsunit/regress/regress-406.js
@@ -0,0 +1,69 @@
+// 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.
+
+// Test of constant folding of boolean-valued expressions.
+
+// See http://code.google.com/p/v8/issues/detail?id=406
+
+assertFalse(typeof(0) == "zero");
+assertTrue(typeof(0) != "zero");
+
+// The and and or truth tables with both operands constant.
+assertFalse(typeof(0) == "zero" && typeof(0) == "zero");
+assertFalse(typeof(0) == "zero" && typeof(0) != "zero");
+assertFalse(typeof(0) != "zero" && typeof(0) == "zero");
+assertTrue(typeof(0) != "zero" && typeof(0) != "zero");
+
+assertFalse(typeof(0) == "zero" || typeof(0) == "zero");
+assertTrue(typeof(0) == "zero" || typeof(0) != "zero");
+assertTrue(typeof(0) != "zero" || typeof(0) == "zero");
+assertTrue(typeof(0) != "zero" || typeof(0) != "zero");
+
+// Same with just the left operand constant.
+// Helper function to prevent simple constant folding.
+function one() { return 1; }
+
+assertFalse(typeof(0) == "zero" && one() < 0);
+assertFalse(typeof(0) == "zero" && one() > 0);
+assertFalse(typeof(0) != "zero" && one() < 0);
+assertTrue(typeof(0) != "zero" && one() > 0);
+
+assertFalse(typeof(0) == "zero" || one() < 0);
+assertTrue(typeof(0) == "zero" || one() > 0);
+assertTrue(typeof(0) != "zero" || one() < 0);
+assertTrue(typeof(0) != "zero" || one() > 0);
+
+// Same with just the right operand constant.
+assertFalse(one() < 0 && typeof(0) == "zero");
+assertFalse(one() < 0 && typeof(0) != "zero");
+assertFalse(one() > 0 && typeof(0) == "zero");
+assertTrue(one() > 0 && typeof(0) != "zero");
+
+assertFalse(one() < 0 || typeof(0) == "zero");
+assertTrue(one() < 0 || typeof(0) != "zero");
+assertTrue(one() > 0 || typeof(0) == "zero");
+assertTrue(one() > 0 || typeof(0) != "zero");
diff --git a/V8Binding/v8/test/mjsunit/tools/codemap.js b/V8Binding/v8/test/mjsunit/tools/codemap.js
index 55b8758..06a91e8 100644
--- a/V8Binding/v8/test/mjsunit/tools/codemap.js
+++ b/V8Binding/v8/test/mjsunit/tools/codemap.js
@@ -46,11 +46,11 @@ function assertNoEntry(codeMap, addr) {
};
-(function testStaticCode() {
+(function testLibrariesAndStaticCode() {
var codeMap = new devtools.profiler.CodeMap();
- codeMap.addStaticCode(0x1500, newCodeEntry(0x3000, 'lib1'));
- codeMap.addStaticCode(0x15500, newCodeEntry(0x5000, 'lib2'));
- codeMap.addStaticCode(0x155500, newCodeEntry(0x10000, 'lib3'));
+ codeMap.addLibrary(0x1500, newCodeEntry(0x3000, 'lib1'));
+ codeMap.addLibrary(0x15500, newCodeEntry(0x5000, 'lib2'));
+ codeMap.addLibrary(0x155500, newCodeEntry(0x10000, 'lib3'));
assertNoEntry(codeMap, 0);
assertNoEntry(codeMap, 0x1500 - 1);
assertEntry(codeMap, 'lib1', 0x1500);
@@ -71,6 +71,28 @@ function assertNoEntry(codeMap, addr) {
assertEntry(codeMap, 'lib3', 0x155500 + 0x10000 - 1);
assertNoEntry(codeMap, 0x155500 + 0x10000);
assertNoEntry(codeMap, 0xFFFFFFFF);
+
+ codeMap.addStaticCode(0x1510, newCodeEntry(0x30, 'lib1-f1'));
+ codeMap.addStaticCode(0x1600, newCodeEntry(0x50, 'lib1-f2'));
+ codeMap.addStaticCode(0x15520, newCodeEntry(0x100, 'lib2-f1'));
+ assertEntry(codeMap, 'lib1', 0x1500);
+ assertEntry(codeMap, 'lib1', 0x1510 - 1);
+ assertEntry(codeMap, 'lib1-f1', 0x1510);
+ assertEntry(codeMap, 'lib1-f1', 0x1510 + 0x15);
+ assertEntry(codeMap, 'lib1-f1', 0x1510 + 0x30 - 1);
+ assertEntry(codeMap, 'lib1', 0x1510 + 0x30);
+ assertEntry(codeMap, 'lib1', 0x1600 - 1);
+ assertEntry(codeMap, 'lib1-f2', 0x1600);
+ assertEntry(codeMap, 'lib1-f2', 0x1600 + 0x30);
+ assertEntry(codeMap, 'lib1-f2', 0x1600 + 0x50 - 1);
+ assertEntry(codeMap, 'lib1', 0x1600 + 0x50);
+ assertEntry(codeMap, 'lib2', 0x15500);
+ assertEntry(codeMap, 'lib2', 0x15520 - 1);
+ assertEntry(codeMap, 'lib2-f1', 0x15520);
+ assertEntry(codeMap, 'lib2-f1', 0x15520 + 0x80);
+ assertEntry(codeMap, 'lib2-f1', 0x15520 + 0x100 - 1);
+ assertEntry(codeMap, 'lib2', 0x15520 + 0x100);
+
})();
diff --git a/V8Binding/v8/test/mjsunit/tools/profile.js b/V8Binding/v8/test/mjsunit/tools/profile.js
index 49eef3b..9ed851b 100644
--- a/V8Binding/v8/test/mjsunit/tools/profile.js
+++ b/V8Binding/v8/test/mjsunit/tools/profile.js
@@ -72,10 +72,10 @@ ProfileTestDriver.prototype.funcAddrs_ = {
ProfileTestDriver.prototype.addFunctions_ = function() {
- this.profile.addStaticCode('lib1', 0x11000, 0x12000);
+ this.profile.addLibrary('lib1', 0x11000, 0x12000);
this.profile.addStaticCode('lib1-f1', 0x11100, 0x11900);
this.profile.addStaticCode('lib1-f2', 0x11200, 0x11500);
- this.profile.addStaticCode('lib2', 0x21000, 0x22000);
+ this.profile.addLibrary('lib2', 0x21000, 0x22000);
this.profile.addStaticCode('lib2-f1', 0x21100, 0x21900);
this.profile.addStaticCode('lib2-f2', 0x21200, 0x21500);
this.profile.addCode('T', 'F1', 0x50100, 0x100);
diff --git a/V8Binding/v8/test/mjsunit/tools/tickprocessor-test.default b/V8Binding/v8/test/mjsunit/tools/tickprocessor-test.default
index a689ea8..702f4bc 100644
--- a/V8Binding/v8/test/mjsunit/tools/tickprocessor-test.default
+++ b/V8Binding/v8/test/mjsunit/tools/tickprocessor-test.default
@@ -6,20 +6,19 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded).
[Shared libraries]:
ticks total nonlib name
- 2 15.4% 0.0% /lib32/libm-2.7.so
+ 3 23.1% 0.0% /lib32/libm-2.7.so
1 7.7% 0.0% ffffe000-fffff000
[JavaScript]:
ticks total nonlib name
- 1 7.7% 10.0% LazyCompile: exp native math.js:41
+ 1 7.7% 11.1% LazyCompile: exp native math.js:41
[C++]:
ticks total nonlib name
- 2 15.4% 20.0% v8::internal::Runtime_Math_exp(v8::internal::Arguments)
- 1 7.7% 10.0% v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
- 1 7.7% 10.0% v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
- 1 7.7% 10.0% fegetexcept
- 1 7.7% 10.0% exp
+ 2 15.4% 22.2% v8::internal::Runtime_Math_exp(v8::internal::Arguments)
+ 1 7.7% 11.1% v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
+ 1 7.7% 11.1% v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
+ 1 7.7% 11.1% exp
[GC]:
ticks total nonlib name
@@ -31,11 +30,11 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded).
Callers occupying less than 2.0% are not shown.
ticks parent name
- 2 15.4% v8::internal::Runtime_Math_exp(v8::internal::Arguments)
- 2 100.0% LazyCompile: exp native math.js:41
- 2 100.0% Script: exp.js
+ 3 23.1% /lib32/libm-2.7.so
+ 3 100.0% LazyCompile: exp native math.js:41
+ 3 100.0% Script: exp.js
- 2 15.4% /lib32/libm-2.7.so
+ 2 15.4% v8::internal::Runtime_Math_exp(v8::internal::Arguments)
2 100.0% LazyCompile: exp native math.js:41
2 100.0% Script: exp.js
@@ -47,10 +46,6 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded).
1 7.7% ffffe000-fffff000
- 1 7.7% fegetexcept
- 1 100.0% LazyCompile: exp native math.js:41
- 1 100.0% Script: exp.js
-
1 7.7% exp
1 100.0% LazyCompile: exp native math.js:41
1 100.0% Script: exp.js
diff --git a/V8Binding/v8/test/mjsunit/tools/tickprocessor-test.ignore-unknown b/V8Binding/v8/test/mjsunit/tools/tickprocessor-test.ignore-unknown
index 87beb08..306d646 100644
--- a/V8Binding/v8/test/mjsunit/tools/tickprocessor-test.ignore-unknown
+++ b/V8Binding/v8/test/mjsunit/tools/tickprocessor-test.ignore-unknown
@@ -2,20 +2,19 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded).
[Shared libraries]:
ticks total nonlib name
- 2 18.2% 0.0% /lib32/libm-2.7.so
+ 3 27.3% 0.0% /lib32/libm-2.7.so
1 9.1% 0.0% ffffe000-fffff000
[JavaScript]:
ticks total nonlib name
- 1 9.1% 12.5% LazyCompile: exp native math.js:41
+ 1 9.1% 14.3% LazyCompile: exp native math.js:41
[C++]:
ticks total nonlib name
- 2 18.2% 25.0% v8::internal::Runtime_Math_exp(v8::internal::Arguments)
- 1 9.1% 12.5% v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
- 1 9.1% 12.5% v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
- 1 9.1% 12.5% fegetexcept
- 1 9.1% 12.5% exp
+ 2 18.2% 28.6% v8::internal::Runtime_Math_exp(v8::internal::Arguments)
+ 1 9.1% 14.3% v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
+ 1 9.1% 14.3% v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
+ 1 9.1% 14.3% exp
[GC]:
ticks total nonlib name
@@ -27,11 +26,11 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded).
Callers occupying less than 2.0% are not shown.
ticks parent name
- 2 18.2% v8::internal::Runtime_Math_exp(v8::internal::Arguments)
- 2 100.0% LazyCompile: exp native math.js:41
- 2 100.0% Script: exp.js
+ 3 27.3% /lib32/libm-2.7.so
+ 3 100.0% LazyCompile: exp native math.js:41
+ 3 100.0% Script: exp.js
- 2 18.2% /lib32/libm-2.7.so
+ 2 18.2% v8::internal::Runtime_Math_exp(v8::internal::Arguments)
2 100.0% LazyCompile: exp native math.js:41
2 100.0% Script: exp.js
@@ -43,10 +42,6 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded).
1 9.1% ffffe000-fffff000
- 1 9.1% fegetexcept
- 1 100.0% LazyCompile: exp native math.js:41
- 1 100.0% Script: exp.js
-
1 9.1% exp
1 100.0% LazyCompile: exp native math.js:41
1 100.0% Script: exp.js
diff --git a/V8Binding/v8/test/mjsunit/tools/tickprocessor-test.separate-ic b/V8Binding/v8/test/mjsunit/tools/tickprocessor-test.separate-ic
index 7eb3d9a..3a2041b 100644
--- a/V8Binding/v8/test/mjsunit/tools/tickprocessor-test.separate-ic
+++ b/V8Binding/v8/test/mjsunit/tools/tickprocessor-test.separate-ic
@@ -6,22 +6,21 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded).
[Shared libraries]:
ticks total nonlib name
- 2 15.4% 0.0% /lib32/libm-2.7.so
+ 3 23.1% 0.0% /lib32/libm-2.7.so
1 7.7% 0.0% ffffe000-fffff000
[JavaScript]:
ticks total nonlib name
- 1 7.7% 10.0% LoadIC: j
- 1 7.7% 10.0% LoadIC: i
- 1 7.7% 10.0% LazyCompile: exp native math.js:41
+ 1 7.7% 11.1% LoadIC: j
+ 1 7.7% 11.1% LoadIC: i
+ 1 7.7% 11.1% LazyCompile: exp native math.js:41
[C++]:
ticks total nonlib name
- 2 15.4% 20.0% v8::internal::Runtime_Math_exp(v8::internal::Arguments)
- 1 7.7% 10.0% v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
- 1 7.7% 10.0% v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
- 1 7.7% 10.0% fegetexcept
- 1 7.7% 10.0% exp
+ 2 15.4% 22.2% v8::internal::Runtime_Math_exp(v8::internal::Arguments)
+ 1 7.7% 11.1% v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::String*, v8::internal::LookupResult*)
+ 1 7.7% 11.1% v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)
+ 1 7.7% 11.1% exp
[GC]:
ticks total nonlib name
@@ -33,11 +32,11 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded).
Callers occupying less than 2.0% are not shown.
ticks parent name
- 2 15.4% v8::internal::Runtime_Math_exp(v8::internal::Arguments)
- 2 100.0% LazyCompile: exp native math.js:41
- 2 100.0% Script: exp.js
+ 3 23.1% /lib32/libm-2.7.so
+ 3 100.0% LazyCompile: exp native math.js:41
+ 3 100.0% Script: exp.js
- 2 15.4% /lib32/libm-2.7.so
+ 2 15.4% v8::internal::Runtime_Math_exp(v8::internal::Arguments)
2 100.0% LazyCompile: exp native math.js:41
2 100.0% Script: exp.js
@@ -49,10 +48,6 @@ Statistical profiling result from v8.log, (13 ticks, 2 unaccounted, 0 excluded).
1 7.7% ffffe000-fffff000
- 1 7.7% fegetexcept
- 1 100.0% LazyCompile: exp native math.js:41
- 1 100.0% Script: exp.js
-
1 7.7% exp
1 100.0% LazyCompile: exp native math.js:41
1 100.0% Script: exp.js
diff --git a/V8Binding/v8/test/mjsunit/tools/tickprocessor.js b/V8Binding/v8/test/mjsunit/tools/tickprocessor.js
index 587106a..00c3fb1 100644
--- a/V8Binding/v8/test/mjsunit/tools/tickprocessor.js
+++ b/V8Binding/v8/test/mjsunit/tools/tickprocessor.js
@@ -31,6 +31,7 @@
// Files: tools/logreader.js tools/tickprocessor.js
// Env: TEST_FILE_NAME
+
(function testArgumentsProcessor() {
var p_default = new ArgumentsProcessor([]);
assertTrue(p_default.parse());
@@ -69,12 +70,12 @@
' U operator delete[](void*)@@GLIBCXX_3.4',
'08049790 T _init',
'08049f50 T _start',
- '08139150 t v8::internal::Runtime_StringReplaceRegExpWithString(v8::internal::Arguments)',
- '08139ca0 T v8::internal::Runtime::GetElementOrCharAt(v8::internal::Handle<v8::internal::Object>, unsigned int)',
- '0813a0b0 t v8::internal::Runtime_DebugGetPropertyDetails(v8::internal::Arguments)',
- '08181d30 W v8::internal::RegExpMacroAssemblerIrregexp::stack_limit_slack()',
+ '08139150 00000b4b t v8::internal::Runtime_StringReplaceRegExpWithString(v8::internal::Arguments)',
+ '08139ca0 000003f1 T v8::internal::Runtime::GetElementOrCharAt(v8::internal::Handle<v8::internal::Object>, unsigned int)',
+ '0813a0b0 00000855 t v8::internal::Runtime_DebugGetPropertyDetails(v8::internal::Arguments)',
+ '0818b220 00000036 W v8::internal::RegExpMacroAssembler::CheckPosition(int, v8::internal::Label*)',
' w __gmon_start__',
- '081f08a0 B stdout'
+ '081f08a0 00000004 B stdout\n'
].join('\n'), ''];
};
@@ -87,22 +88,22 @@
assertEquals(
[['_init', 0x08049790, 0x08049f50],
['_start', 0x08049f50, 0x08139150],
- ['v8::internal::Runtime_StringReplaceRegExpWithString(v8::internal::Arguments)', 0x08139150, 0x08139ca0],
- ['v8::internal::Runtime::GetElementOrCharAt(v8::internal::Handle<v8::internal::Object>, unsigned int)', 0x08139ca0, 0x0813a0b0],
- ['v8::internal::Runtime_DebugGetPropertyDetails(v8::internal::Arguments)', 0x0813a0b0, 0x08181d30],
- ['v8::internal::RegExpMacroAssemblerIrregexp::stack_limit_slack()', 0x08181d30, 0x081ee000]],
+ ['v8::internal::Runtime_StringReplaceRegExpWithString(v8::internal::Arguments)', 0x08139150, 0x08139150 + 0xb4b],
+ ['v8::internal::Runtime::GetElementOrCharAt(v8::internal::Handle<v8::internal::Object>, unsigned int)', 0x08139ca0, 0x08139ca0 + 0x3f1],
+ ['v8::internal::Runtime_DebugGetPropertyDetails(v8::internal::Arguments)', 0x0813a0b0, 0x0813a0b0 + 0x855],
+ ['v8::internal::RegExpMacroAssembler::CheckPosition(int, v8::internal::Label*)', 0x0818b220, 0x0818b220 + 0x36]],
shell_syms);
// libc library
UnixCppEntriesProvider.prototype.loadSymbols = function(libName) {
this.symbols = [[
- '000162a0 T __libc_init_first',
- '0002a5f0 T __isnan',
- '0002a5f0 W isnan',
- '0002aaa0 W scalblnf',
- '0002aaa0 W scalbnf',
- '0011a340 T __libc_thread_freeres',
- '00128860 R _itoa_lower_digits'].join('\n'), ''];
+ '000162a0 00000005 T __libc_init_first',
+ '0002a5f0 0000002d T __isnan',
+ '0002a5f0 0000002d W isnan',
+ '0002aaa0 0000000d W scalblnf',
+ '0002aaa0 0000000d W scalbnf',
+ '0011a340 00000048 T __libc_thread_freeres',
+ '00128860 00000024 R _itoa_lower_digits\n'].join('\n'), ''];
};
var libc_prov = new UnixCppEntriesProvider();
var libc_syms = [];
@@ -110,17 +111,81 @@
function (name, start, end) {
libc_syms.push(Array.prototype.slice.apply(arguments, [0]));
});
- assertEquals(
- [['__libc_init_first', 0xf7c5c000 + 0x000162a0, 0xf7c5c000 + 0x0002a5f0],
- ['isnan', 0xf7c5c000 + 0x0002a5f0, 0xf7c5c000 + 0x0002aaa0],
- ['scalbnf', 0xf7c5c000 + 0x0002aaa0, 0xf7c5c000 + 0x0011a340],
- ['__libc_thread_freeres', 0xf7c5c000 + 0x0011a340, 0xf7da5000]],
- libc_syms);
+ var libc_ref_syms = [['__libc_init_first', 0x000162a0, 0x000162a0 + 0x5],
+ ['__isnan', 0x0002a5f0, 0x0002a5f0 + 0x2d],
+ ['scalblnf', 0x0002aaa0, 0x0002aaa0 + 0xd],
+ ['__libc_thread_freeres', 0x0011a340, 0x0011a340 + 0x48]];
+ for (var i = 0; i < libc_ref_syms.length; ++i) {
+ libc_ref_syms[i][1] += 0xf7c5c000;
+ libc_ref_syms[i][2] += 0xf7c5c000;
+ }
+ assertEquals(libc_ref_syms, libc_syms);
UnixCppEntriesProvider.prototype.loadSymbols = oldLoadSymbols;
})();
+(function testMacCppEntriesProvider() {
+ var oldLoadSymbols = MacCppEntriesProvider.prototype.loadSymbols;
+
+ // shell executable
+ MacCppEntriesProvider.prototype.loadSymbols = function(libName) {
+ this.symbols = [[
+ ' U operator delete[]',
+ '00001000 A __mh_execute_header',
+ '00001b00 T start',
+ '00001b40 t dyld_stub_binding_helper',
+ '0011b710 T v8::internal::RegExpMacroAssembler::CheckPosition',
+ '00134250 t v8::internal::Runtime_StringReplaceRegExpWithString',
+ '00137220 T v8::internal::Runtime::GetElementOrCharAt',
+ '00137400 t v8::internal::Runtime_DebugGetPropertyDetails',
+ '001c1a80 b _private_mem\n'
+ ].join('\n'), ''];
+ };
+
+ var shell_prov = new MacCppEntriesProvider();
+ var shell_syms = [];
+ shell_prov.parseVmSymbols('shell', 0x00001b00, 0x00163156,
+ function (name, start, end) {
+ shell_syms.push(Array.prototype.slice.apply(arguments, [0]));
+ });
+ assertEquals(
+ [['start', 0x00001b00, 0x00001b40],
+ ['dyld_stub_binding_helper', 0x00001b40, 0x0011b710],
+ ['v8::internal::RegExpMacroAssembler::CheckPosition', 0x0011b710, 0x00134250],
+ ['v8::internal::Runtime_StringReplaceRegExpWithString', 0x00134250, 0x00137220],
+ ['v8::internal::Runtime::GetElementOrCharAt', 0x00137220, 0x00137400],
+ ['v8::internal::Runtime_DebugGetPropertyDetails', 0x00137400, 0x00163156]],
+ shell_syms);
+
+ // stdc++ library
+ MacCppEntriesProvider.prototype.loadSymbols = function(libName) {
+ this.symbols = [[
+ '0000107a T __gnu_cxx::balloc::__mini_vector<std::pair<__gnu_cxx::bitmap_allocator<char>::_Alloc_block*, __gnu_cxx::bitmap_allocator<char>::_Alloc_block*> >::__mini_vector',
+ '0002c410 T std::basic_streambuf<char, std::char_traits<char> >::pubseekoff',
+ '0002c488 T std::basic_streambuf<char, std::char_traits<char> >::pubseekpos',
+ '000466aa T ___cxa_pure_virtual\n'].join('\n'), ''];
+ };
+ var stdc_prov = new MacCppEntriesProvider();
+ var stdc_syms = [];
+ stdc_prov.parseVmSymbols('stdc++', 0x95728fb4, 0x95770005,
+ function (name, start, end) {
+ stdc_syms.push(Array.prototype.slice.apply(arguments, [0]));
+ });
+ var stdc_ref_syms = [['__gnu_cxx::balloc::__mini_vector<std::pair<__gnu_cxx::bitmap_allocator<char>::_Alloc_block*, __gnu_cxx::bitmap_allocator<char>::_Alloc_block*> >::__mini_vector', 0x0000107a, 0x0002c410],
+ ['std::basic_streambuf<char, std::char_traits<char> >::pubseekoff', 0x0002c410, 0x0002c488],
+ ['std::basic_streambuf<char, std::char_traits<char> >::pubseekpos', 0x0002c488, 0x000466aa],
+ ['___cxa_pure_virtual', 0x000466aa, 0x95770005 - 0x95728fb4]];
+ for (var i = 0; i < stdc_ref_syms.length; ++i) {
+ stdc_ref_syms[i][1] += 0x95728fb4;
+ stdc_ref_syms[i][2] += 0x95728fb4;
+ }
+ assertEquals(stdc_ref_syms, stdc_syms);
+
+ MacCppEntriesProvider.prototype.loadSymbols = oldLoadSymbols;
+})();
+
+
(function testWindowsCppEntriesProvider() {
var oldLoadSymbols = WindowsCppEntriesProvider.prototype.loadSymbols;
@@ -174,8 +239,8 @@ CppEntriesProviderMock.prototype.parseVmSymbols = function(
['v8::internal::HashTable<v8::internal::StringDictionaryShape, v8::internal::String*>::FindEntry(v8::internal::String*)', 0x080f8210, 0x080f8800],
['v8::internal::Runtime_Math_exp(v8::internal::Arguments)', 0x08123b20, 0x08123b80]],
'/lib32/libm-2.7.so':
- [['exp', startAddr + 0x00009e80, startAddr + 0x00009f30],
- ['fegetexcept', startAddr + 0x000061e0, startAddr + 0x00008b10]],
+ [['exp', startAddr + 0x00009e80, startAddr + 0x00009e80 + 0xa3],
+ ['fegetexcept', startAddr + 0x000061e0, startAddr + 0x000061e0 + 0x15]],
'ffffe000-fffff000': []};
assertTrue(name in symbols);
var syms = symbols[name];
@@ -191,6 +256,7 @@ function PrintMonitor(outputOrFileName) {
var outputPos = 0;
var diffs = this.diffs = [];
var realOut = this.realOut = [];
+ var unexpectedOut = this.unexpectedOut = null;
this.oldPrint = print;
print = function(str) {
@@ -198,13 +264,15 @@ function PrintMonitor(outputOrFileName) {
for (var i = 0; i < strSplit.length; ++i) {
s = strSplit[i];
realOut.push(s);
- assertTrue(outputPos < expectedOut.length,
- 'unexpected output: "' + s + '"');
- if (expectedOut[outputPos] != s) {
- diffs.push('line ' + outputPos + ': expected <' +
- expectedOut[outputPos] + '> found <' + s + '>\n');
+ if (outputPos < expectedOut.length) {
+ if (expectedOut[outputPos] != s) {
+ diffs.push('line ' + outputPos + ': expected <' +
+ expectedOut[outputPos] + '> found <' + s + '>\n');
+ }
+ outputPos++;
+ } else {
+ unexpectedOut = true;
}
- outputPos++;
}
};
};
@@ -218,9 +286,10 @@ PrintMonitor.prototype.loadExpectedOutput = function(fileName) {
PrintMonitor.prototype.finish = function() {
print = this.oldPrint;
- if (this.diffs.length > 0) {
+ if (this.diffs.length > 0 || this.unexpectedOut != null) {
print(this.realOut.join('\n'));
assertEquals([], this.diffs);
+ assertNull(this.unexpectedOut);
}
};
diff --git a/V8Binding/v8/test/mozilla/mozilla.status b/V8Binding/v8/test/mozilla/mozilla.status
index 13ae29c..538b0a8 100644
--- a/V8Binding/v8/test/mozilla/mozilla.status
+++ b/V8Binding/v8/test/mozilla/mozilla.status
@@ -321,10 +321,6 @@ js1_5/Regress/regress-179524: FAIL_OK
js1_5/Regress/regress-172699: FAIL_OK
-# Calls regexp objects with function call syntax; non-ECMA behavior.
-js1_2/Objects/toString-001: FAIL_OK
-
-
# Assumes that the prototype of a function is enumerable. Non-ECMA,
# see section 15.3.3.1, page 86.
ecma/GlobalObject/15.1.2.2-1: FAIL_OK
@@ -338,6 +334,7 @@ ecma/GlobalObject/15.1.2.7: FAIL_OK
# Tests that rely on specific details of function decompilation or
# print strings for errors. Non-ECMA behavior.
js1_2/function/tostring-2: FAIL_OK
+js1_2/Objects/toString-001: FAIL_OK
js1_5/Exceptions/regress-332472: FAIL_OK
js1_5/Regress/regress-173067: FAIL_OK
js1_5/Regress/regress-355556: FAIL_OK
@@ -561,23 +558,11 @@ js1_5/Array/regress-350256-02: FAIL
ecma_3/Function/regress-137181: FAIL
-# Calls regexp objects with function call syntax; non-ECMA behavior.
-ecma_2/RegExp/regress-001: FAIL
-js1_2/regexp/regress-6359: FAIL
-js1_2/regexp/regress-9141: FAIL
-js1_5/Regress/regress-224956: FAIL
-js1_5/Regress/regress-325925: FAIL
-js1_2/regexp/simple_form: FAIL
-
-
# Tests that rely on specific details of function decompilation or
# print strings for errors. Non-ECMA behavior.
js1_4/Regress/function-003: FAIL
-# Relies on JavaScript 1.2 / 1.3 deprecated features.
-js1_2/function/regexparg-1: FAIL
-
# 'export' and 'import' are not keywords in V8.
ecma_2/Exceptions/lexical-010: FAIL
ecma_2/Exceptions/lexical-022: FAIL
diff --git a/V8Binding/v8/tools/codemap.js b/V8Binding/v8/tools/codemap.js
index d6df7fa..404127f 100644
--- a/V8Binding/v8/tools/codemap.js
+++ b/V8Binding/v8/tools/codemap.js
@@ -48,11 +48,16 @@ devtools.profiler.CodeMap = function() {
this.dynamicsNameGen_ = new devtools.profiler.CodeMap.NameGenerator();
/**
- * Static code entries. Used for libraries code.
+ * Static code entries. Used for statically compiled code.
*/
this.statics_ = new goog.structs.SplayTree();
/**
+ * Libraries entries. Used for the whole static code libraries.
+ */
+ this.libraries_ = new goog.structs.SplayTree();
+
+ /**
* Map of memory pages occupied with static code.
*/
this.pages_ = [];
@@ -108,6 +113,19 @@ devtools.profiler.CodeMap.prototype.deleteCode = function(start) {
/**
+ * Adds a library entry.
+ *
+ * @param {number} start The starting address.
+ * @param {devtools.profiler.CodeMap.CodeEntry} codeEntry Code entry object.
+ */
+devtools.profiler.CodeMap.prototype.addLibrary = function(
+ start, codeEntry) {
+ this.markPages_(start, start + codeEntry.size);
+ this.libraries_.insert(start, codeEntry);
+};
+
+
+/**
* Adds a static code entry.
*
* @param {number} start The starting address.
@@ -115,7 +133,6 @@ devtools.profiler.CodeMap.prototype.deleteCode = function(start) {
*/
devtools.profiler.CodeMap.prototype.addStaticCode = function(
start, codeEntry) {
- this.markPages_(start, start + codeEntry.size);
this.statics_.insert(start, codeEntry);
};
@@ -157,7 +174,10 @@ devtools.profiler.CodeMap.prototype.findInTree_ = function(tree, addr) {
devtools.profiler.CodeMap.prototype.findEntry = function(addr) {
var pageAddr = addr >>> devtools.profiler.CodeMap.PAGE_ALIGNMENT;
if (pageAddr in this.pages_) {
- return this.findInTree_(this.statics_, addr);
+ // Static code entries can contain "holes" of unnamed code.
+ // In this case, the whole library is assigned to this address.
+ return this.findInTree_(this.statics_, addr) ||
+ this.findInTree_(this.libraries_, addr);
}
var min = this.dynamics_.findMin();
var max = this.dynamics_.findMax();
@@ -176,7 +196,7 @@ devtools.profiler.CodeMap.prototype.findEntry = function(addr) {
/**
- * Returns an array of all dynamic code entries, including deleted ones.
+ * Returns an array of all dynamic code entries.
*/
devtools.profiler.CodeMap.prototype.getAllDynamicEntries = function() {
return this.dynamics_.exportValues();
@@ -192,6 +212,14 @@ devtools.profiler.CodeMap.prototype.getAllStaticEntries = function() {
/**
+ * Returns an array of all libraries entries.
+ */
+devtools.profiler.CodeMap.prototype.getAllLibrariesEntries = function() {
+ return this.libraries_.exportValues();
+};
+
+
+/**
* Creates a code entry object.
*
* @param {number} size Code entry size in bytes.
diff --git a/V8Binding/v8/tools/gyp/v8.gyp b/V8Binding/v8/tools/gyp/v8.gyp
index b11a7ff..fc49620 100644
--- a/V8Binding/v8/tools/gyp/v8.gyp
+++ b/V8Binding/v8/tools/gyp/v8.gyp
@@ -254,6 +254,7 @@
'../../src/frames-inl.h',
'../../src/frames.cc',
'../../src/frames.h',
+ '../../src/frame-element.cc',
'../../src/frame-element.h',
'../../src/func-name-inferrer.cc',
'../../src/func-name-inferrer.h',
diff --git a/V8Binding/v8/tools/mac-nm b/V8Binding/v8/tools/mac-nm
new file mode 100755
index 0000000..9c18177
--- /dev/null
+++ b/V8Binding/v8/tools/mac-nm
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+# This script is a wrapper for OS X nm(1) tool. nm(1) perform C++ function
+# names demangling, so we're piping its output to c++filt(1) tool which does it.
+# But c++filt(1) comes with XCode (as a part of GNU binutils), so it doesn't
+# guaranteed to exist on a system.
+#
+# An alternative approach is to perform demangling in tick processor, but
+# for GNU C++ ABI this is a complex process (see cp-demangle.c sources), and
+# can't be done partially, because term boundaries are plain text symbols, such
+# as 'N', 'E', so one can't just do a search through a function name, it really
+# needs to be parsed, which requires a lot of knowledge to be coded in.
+
+if [ "`which c++filt`" == "" ]; then
+ nm $@
+else
+ nm $@ | c++filt -p -i
+fi
diff --git a/V8Binding/v8/tools/mac-tick-processor b/V8Binding/v8/tools/mac-tick-processor
new file mode 100755
index 0000000..5fba622
--- /dev/null
+++ b/V8Binding/v8/tools/mac-tick-processor
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# A wrapper script to call 'linux-tick-processor' with Mac-specific settings.
+
+tools_path=`cd $(dirname "$0");pwd`
+$tools_path/linux-tick-processor --mac --nm=$tools_path/mac-nm $@
diff --git a/V8Binding/v8/tools/process-heap-prof.py b/V8Binding/v8/tools/process-heap-prof.py
new file mode 100755
index 0000000..b8ab2d3
--- /dev/null
+++ b/V8Binding/v8/tools/process-heap-prof.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+#
+# 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.
+
+# This is an utility for converting V8 heap logs into .hp files that can
+# be further processed using 'hp2ps' tool (bundled with GHC and Valgrind)
+# to produce heap usage histograms.
+
+# Sample usage:
+# $ ./shell --log-gc script.js
+# $ tools/process-heap-prof.py v8.log | hp2ps -c > script-heap-graph.ps
+# ('-c' enables color, see hp2ps manual page for more options)
+
+import csv, sys, time
+
+def process_logfile(filename):
+ first_call_time = None
+ sample_time = 0.0
+ sampling = False
+ try:
+ logfile = open(filename, 'rb')
+ try:
+ logreader = csv.reader(logfile)
+
+ print('JOB "v8"')
+ print('DATE "%s"' % time.asctime(time.localtime()))
+ print('SAMPLE_UNIT "seconds"')
+ print('VALUE_UNIT "bytes"')
+
+ for row in logreader:
+ if row[0] == 'heap-sample-begin' and row[1] == 'Heap':
+ sample_time = float(row[3])/1000.0
+ if first_call_time == None:
+ first_call_time = sample_time
+ sample_time -= first_call_time
+ print('BEGIN_SAMPLE %.2f' % sample_time)
+ sampling = True
+ elif row[0] == 'heap-sample-end' and row[1] == 'Heap':
+ print('END_SAMPLE %.2f' % sample_time)
+ sampling = False
+ elif row[0] == 'heap-sample-item' and sampling:
+ print('%s %d' % (row[1], int(row[3])))
+ finally:
+ logfile.close()
+ except:
+ sys.exit('can\'t open %s' % filename)
+
+process_logfile(sys.argv[1])
diff --git a/V8Binding/v8/tools/profile.js b/V8Binding/v8/tools/profile.js
index 614c635..db4b542 100644
--- a/V8Binding/v8/tools/profile.js
+++ b/V8Binding/v8/tools/profile.js
@@ -86,7 +86,23 @@ devtools.profiler.Profile.prototype.handleUnknownCode = function(
/**
- * Registers static (library) code entry.
+ * Registers a library.
+ *
+ * @param {string} name Code entry name.
+ * @param {number} startAddr Starting address.
+ * @param {number} endAddr Ending address.
+ */
+devtools.profiler.Profile.prototype.addLibrary = function(
+ name, startAddr, endAddr) {
+ var entry = new devtools.profiler.CodeMap.CodeEntry(
+ endAddr - startAddr, name);
+ this.codeMap_.addLibrary(startAddr, entry);
+ return entry;
+};
+
+
+/**
+ * Registers statically compiled code entry.
*
* @param {string} name Code entry name.
* @param {number} startAddr Starting address.
diff --git a/V8Binding/v8/tools/test.py b/V8Binding/v8/tools/test.py
index 05eb9fd..c1b8b80 100755
--- a/V8Binding/v8/tools/test.py
+++ b/V8Binding/v8/tools/test.py
@@ -1136,6 +1136,7 @@ def ProcessOptions(options):
# was found, set the arch to the guess.
if options.arch == 'none':
options.arch = ARCH_GUESS
+ options.scons_flags.append("arch=" + options.arch)
return True
diff --git a/V8Binding/v8/tools/tickprocessor-driver.js b/V8Binding/v8/tools/tickprocessor-driver.js
index f7cfd13..dc67796 100644
--- a/V8Binding/v8/tools/tickprocessor-driver.js
+++ b/V8Binding/v8/tools/tickprocessor-driver.js
@@ -37,11 +37,15 @@ function processArguments(args) {
}
}
+var entriesProviders = {
+ 'unix': UnixCppEntriesProvider,
+ 'windows': WindowsCppEntriesProvider,
+ 'mac': MacCppEntriesProvider
+};
var params = processArguments(arguments);
var tickProcessor = new TickProcessor(
- params.platform == 'unix' ? new UnixCppEntriesProvider(params.nm) :
- new WindowsCppEntriesProvider(),
+ new (entriesProviders[params.platform])(params.nm),
params.separateIc,
params.ignoreUnknown,
params.stateFilter);
diff --git a/V8Binding/v8/tools/tickprocessor.js b/V8Binding/v8/tools/tickprocessor.js
index c95a4e6..efd9750 100644
--- a/V8Binding/v8/tools/tickprocessor.js
+++ b/V8Binding/v8/tools/tickprocessor.js
@@ -174,7 +174,7 @@ TickProcessor.prototype.processLogFile = function(fileName) {
TickProcessor.prototype.processSharedLibrary = function(
name, startAddr, endAddr) {
- var entry = this.profile_.addStaticCode(name, startAddr, endAddr);
+ var entry = this.profile_.addLibrary(name, startAddr, endAddr);
this.setCodeType(entry.getName(), 'SHARED_LIB');
var self = this;
@@ -380,14 +380,21 @@ CppEntriesProvider.prototype.parseVmSymbols = function(
var prevEntry;
- function addPrevEntry(end) {
+ function addEntry(funcInfo) {
// Several functions can be mapped onto the same address. To avoid
// creating zero-sized entries, skip such duplicates.
// Also double-check that function belongs to the library address space.
- if (prevEntry && prevEntry.start < end &&
- prevEntry.start >= libStart && end <= libEnd) {
- processorFunc(prevEntry.name, prevEntry.start, end);
+ if (prevEntry && !prevEntry.end &&
+ prevEntry.start < funcInfo.start &&
+ prevEntry.start >= libStart && funcInfo.start <= libEnd) {
+ processorFunc(prevEntry.name, prevEntry.start, funcInfo.start);
}
+ if (funcInfo.end &&
+ (!prevEntry || prevEntry.start != funcInfo.start) &&
+ funcInfo.start >= libStart && funcInfo.end <= libEnd) {
+ processorFunc(funcInfo.name, funcInfo.start, funcInfo.end);
+ }
+ prevEntry = funcInfo;
}
while (true) {
@@ -400,10 +407,12 @@ CppEntriesProvider.prototype.parseVmSymbols = function(
if (funcInfo.start < libStart && funcInfo.start < libEnd - libStart) {
funcInfo.start += libStart;
}
- addPrevEntry(funcInfo.start);
- prevEntry = funcInfo;
+ if (funcInfo.size) {
+ funcInfo.end = funcInfo.start + funcInfo.size;
+ }
+ addEntry(funcInfo);
}
- addPrevEntry(libEnd);
+ addEntry({name: '', start: libEnd});
};
@@ -420,19 +429,17 @@ function UnixCppEntriesProvider(nmExec) {
this.symbols = [];
this.parsePos = 0;
this.nmExec = nmExec;
+ this.FUNC_RE = /^([0-9a-fA-F]{8}) ([0-9a-fA-F]{8} )?[tTwW] (.*)$/;
};
inherits(UnixCppEntriesProvider, CppEntriesProvider);
-UnixCppEntriesProvider.FUNC_RE = /^([0-9a-fA-F]{8}) [tTwW] (.*)$/;
-
-
UnixCppEntriesProvider.prototype.loadSymbols = function(libName) {
this.parsePos = 0;
try {
this.symbols = [
- os.system(this.nmExec, ['-C', '-n', libName], -1, -1),
- os.system(this.nmExec, ['-C', '-n', '-D', libName], -1, -1)
+ os.system(this.nmExec, ['-C', '-n', '-S', libName], -1, -1),
+ os.system(this.nmExec, ['-C', '-n', '-S', '-D', libName], -1, -1)
];
} catch (e) {
// If the library cannot be found on this system let's not panic.
@@ -454,8 +461,34 @@ UnixCppEntriesProvider.prototype.parseNextLine = function() {
var line = this.symbols[0].substring(this.parsePos, lineEndPos);
this.parsePos = lineEndPos + 1;
- var fields = line.match(UnixCppEntriesProvider.FUNC_RE);
- return fields ? { name: fields[2], start: parseInt(fields[1], 16) } : null;
+ var fields = line.match(this.FUNC_RE);
+ var funcInfo = null;
+ if (fields) {
+ funcInfo = { name: fields[3], start: parseInt(fields[1], 16) };
+ if (fields[2]) {
+ funcInfo.size = parseInt(fields[2], 16);
+ }
+ }
+ return funcInfo;
+};
+
+
+function MacCppEntriesProvider(nmExec) {
+ UnixCppEntriesProvider.call(this, nmExec);
+ // Note an empty group. It is required, as UnixCppEntriesProvider expects 3 groups.
+ this.FUNC_RE = /^([0-9a-fA-F]{8}) ()[iItT] (.*)$/;
+};
+inherits(MacCppEntriesProvider, UnixCppEntriesProvider);
+
+
+MacCppEntriesProvider.prototype.loadSymbols = function(libName) {
+ this.parsePos = 0;
+ try {
+ this.symbols = [os.system(this.nmExec, ['-n', '-f', libName], -1, -1), ''];
+ } catch (e) {
+ // If the library cannot be found on this system let's not panic.
+ this.symbols = '';
+ }
};
@@ -538,6 +571,8 @@ function ArgumentsProcessor(args) {
'Specify that we are running on *nix platform'],
'--windows': ['platform', 'windows',
'Specify that we are running on Windows platform'],
+ '--mac': ['platform', 'mac',
+ 'Specify that we are running on Mac OS X platform'],
'--nm': ['nm', 'nm',
'Specify the \'nm\' executable to use (e.g. --nm=/my_dir/nm)']
};
diff --git a/V8Binding/v8/tools/v8.xcodeproj/project.pbxproj b/V8Binding/v8/tools/v8.xcodeproj/project.pbxproj
index 368ba3f..da155b8 100644
--- a/V8Binding/v8/tools/v8.xcodeproj/project.pbxproj
+++ b/V8Binding/v8/tools/v8.xcodeproj/project.pbxproj
@@ -59,6 +59,8 @@
896FD03A0E78D717003DFB6A /* libv8-arm.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 89F23C870E78D5B2006B2466 /* libv8-arm.a */; };
897F767F0E71B690007ACF34 /* shell.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1B50E719C0900D62E90 /* shell.cc */; };
897F76850E71B6B1007ACF34 /* libv8.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8970F2F00E719FB2006AE7B5 /* libv8.a */; };
+ 8981F6001010501900D1520E /* frame-element.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8981F5FE1010500F00D1520E /* frame-element.cc */; };
+ 8981F6011010502800D1520E /* frame-element.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8981F5FE1010500F00D1520E /* frame-element.cc */; };
898BD20E0EF6CC930068B00A /* debug-ia32.cc in Sources */ = {isa = PBXBuildFile; fileRef = 898BD20D0EF6CC850068B00A /* debug-ia32.cc */; };
898BD20F0EF6CC9A0068B00A /* debug-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 898BD20C0EF6CC850068B00A /* debug-arm.cc */; };
89A15C7B0EE466EB00B48DEB /* regexp-macro-assembler-ia32.cc in Sources */ = {isa = PBXBuildFile; fileRef = 89A15C720EE466D000B48DEB /* regexp-macro-assembler-ia32.cc */; };
@@ -503,6 +505,8 @@
897FF1B70E719C2E00D62E90 /* macros.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; name = macros.py; path = ../src/macros.py; sourceTree = "<group>"; };
897FF32F0FAA0ED200136CF6 /* version.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = version.cc; sourceTree = "<group>"; };
897FF3300FAA0ED200136CF6 /* version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = version.h; sourceTree = "<group>"; };
+ 8981F5FE1010500F00D1520E /* frame-element.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "frame-element.cc"; sourceTree = "<group>"; };
+ 8981F5FF1010500F00D1520E /* frame-element.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "frame-element.h"; sourceTree = "<group>"; };
898BD20C0EF6CC850068B00A /* debug-arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "debug-arm.cc"; path = "arm/debug-arm.cc"; sourceTree = "<group>"; };
898BD20D0EF6CC850068B00A /* debug-ia32.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "debug-ia32.cc"; path = "ia32/debug-ia32.cc"; sourceTree = "<group>"; };
89A15C630EE4661A00B48DEB /* bytecodes-irregexp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "bytecodes-irregexp.h"; sourceTree = "<group>"; };
@@ -700,6 +704,8 @@
89471C7F0EB23EE400B6874B /* flag-definitions.h */,
897FF1350E719B8F00D62E90 /* flags.cc */,
897FF1360E719B8F00D62E90 /* flags.h */,
+ 8981F5FE1010500F00D1520E /* frame-element.cc */,
+ 8981F5FF1010500F00D1520E /* frame-element.h */,
897FF1370E719B8F00D62E90 /* frames-arm.cc */,
897FF1380E719B8F00D62E90 /* frames-arm.h */,
897FF1390E719B8F00D62E90 /* frames-ia32.cc */,
@@ -1196,6 +1202,7 @@
58950D670F5551C400F3E8BA /* virtual-frame-ia32.cc in Sources */,
89A88E2E0E71A6D60043BA31 /* zone.cc in Sources */,
9F4B7B890FCC877A00DC4117 /* log-utils.cc in Sources */,
+ 8981F6001010501900D1520E /* frame-element.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1300,6 +1307,7 @@
58950D690F5551CE00F3E8BA /* virtual-frame-arm.cc in Sources */,
89F23C820E78D5B2006B2466 /* zone.cc in Sources */,
9F4B7B8A0FCC877A00DC4117 /* log-utils.cc in Sources */,
+ 8981F6011010502800D1520E /* frame-element.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/V8Binding/v8/tools/visual_studio/v8_base.vcproj b/V8Binding/v8/tools/visual_studio/v8_base.vcproj
index bfdcec9..ece631a 100644
--- a/V8Binding/v8/tools/visual_studio/v8_base.vcproj
+++ b/V8Binding/v8/tools/visual_studio/v8_base.vcproj
@@ -397,19 +397,23 @@
>
</File>
<File
- RelativePath="..\..\src\ia32\frames-ia32.cc"
+ RelativePath="..\..\src\frame-element.cc"
>
</File>
<File
- RelativePath="..\..\src\ia32\frames-ia32.h"
+ RelativePath="..\..\src\frame-element.h"
>
</File>
<File
- RelativePath="..\..\src\frames-inl.h"
+ RelativePath="..\..\src\ia32\frames-ia32.cc"
>
</File>
<File
- RelativePath="..\..\src\frame-element.h"
+ RelativePath="..\..\src\ia32\frames-ia32.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\frames-inl.h"
>
</File>
<File
diff --git a/V8Binding/v8/tools/visual_studio/v8_base_arm.vcproj b/V8Binding/v8/tools/visual_studio/v8_base_arm.vcproj
index 8ebe386..d73747e 100644
--- a/V8Binding/v8/tools/visual_studio/v8_base_arm.vcproj
+++ b/V8Binding/v8/tools/visual_studio/v8_base_arm.vcproj
@@ -401,6 +401,14 @@
>
</File>
<File
+ RelativePath="..\..\src\frame-element.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\frame-element.h"
+ >
+ </File>
+ <File
RelativePath="..\..\src\arm\frames-arm.cc"
>
</File>
diff --git a/WEBKIT_MERGE_REVISION b/WEBKIT_MERGE_REVISION
index e66dc02..4706c2d 100644
--- a/WEBKIT_MERGE_REVISION
+++ b/WEBKIT_MERGE_REVISION
@@ -2,4 +2,4 @@ We sync with Chromium release revision, which has both webkit revision and V8 re
http://src.chromium.org/svn/branches/187/src@18043
http://svn.webkit.org/repository/webkit/trunk@44544
- http://v8.googlecode.com/svn/branches/bleeding_edge@2450
+ http://v8.googlecode.com/svn/branches/bleeding_edge@2530
diff --git a/WebCore/platform/SharedBuffer.h b/WebCore/platform/SharedBuffer.h
index 3404a0c..cd918d6 100644
--- a/WebCore/platform/SharedBuffer.h
+++ b/WebCore/platform/SharedBuffer.h
@@ -61,7 +61,10 @@ public:
// The buffer must be in non-purgeable state before adopted to a SharedBuffer.
// It will stay that way until released.
static PassRefPtr<SharedBuffer> adoptPurgeableBuffer(PurgeableBuffer* buffer);
-
+
+#if PLATFORM(ANDROID)
+ virtual
+#endif
~SharedBuffer();
#if PLATFORM(MAC)
@@ -73,7 +76,13 @@ public:
static PassRefPtr<SharedBuffer> wrapCFData(CFDataRef);
#endif
+#if PLATFORM(ANDROID)
+ virtual
+#endif
const char* data() const;
+#if PLATFORM(ANDROID)
+ virtual
+#endif
unsigned size() const;
const Vector<char> &buffer() { return m_buffer; }