summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--deps/v8/AUTHORS1
-rw-r--r--deps/v8/ChangeLog24
-rw-r--r--deps/v8/LICENSE13
-rw-r--r--deps/v8/include/v8.h17
-rwxr-xr-xdeps/v8/src/SConscript17
-rw-r--r--deps/v8/src/api.cc9
-rw-r--r--deps/v8/src/arm/builtins-arm.cc16
-rw-r--r--deps/v8/src/arm/codegen-arm.cc2
-rw-r--r--deps/v8/src/arm/constants-arm.h24
-rw-r--r--deps/v8/src/arm/macro-assembler-arm.cc16
-rw-r--r--deps/v8/src/bootstrapper.cc4
-rw-r--r--deps/v8/src/builtins.cc6
-rw-r--r--deps/v8/src/builtins.h11
-rw-r--r--deps/v8/src/handles.cc85
-rw-r--r--deps/v8/src/handles.h6
-rw-r--r--deps/v8/src/heap-profiler.cc548
-rw-r--r--deps/v8/src/heap-profiler.h266
-rw-r--r--deps/v8/src/heap.cc178
-rw-r--r--deps/v8/src/heap.h14
-rw-r--r--deps/v8/src/ia32/builtins-ia32.cc460
-rw-r--r--deps/v8/src/log-utils.cc14
-rw-r--r--deps/v8/src/log-utils.h9
-rw-r--r--deps/v8/src/log.cc43
-rw-r--r--deps/v8/src/log.h2
-rw-r--r--deps/v8/src/mark-compact.cc49
-rw-r--r--deps/v8/src/messages.js3
-rw-r--r--deps/v8/src/objects-debug.cc1
-rw-r--r--deps/v8/src/objects-inl.h10
-rw-r--r--deps/v8/src/objects.cc98
-rw-r--r--deps/v8/src/objects.h30
-rw-r--r--deps/v8/src/runtime.cc107
-rw-r--r--deps/v8/src/runtime.h3
-rw-r--r--deps/v8/src/serialize.cc38
-rw-r--r--deps/v8/src/serialize.h3
-rw-r--r--deps/v8/src/spaces.cc14
-rw-r--r--deps/v8/src/string-stream.cc2
-rw-r--r--deps/v8/src/string-stream.h2
-rw-r--r--deps/v8/src/v8-counters.h2
-rw-r--r--deps/v8/src/v8natives.js18
-rw-r--r--deps/v8/src/version.cc4
-rw-r--r--deps/v8/src/x64/builtins-x64.cc16
-rw-r--r--deps/v8/src/zone-inl.h19
-rw-r--r--deps/v8/src/zone.h8
-rw-r--r--deps/v8/test/cctest/SConscript1
-rw-r--r--deps/v8/test/cctest/test-heap-profiler.cc330
-rw-r--r--deps/v8/test/es5conform/README14
-rw-r--r--deps/v8/test/es5conform/es5conform.status68
-rw-r--r--deps/v8/test/es5conform/harness-adapt.js (renamed from deps/v8/test/mjsunit/array-splice-webkit.js)78
-rw-r--r--deps/v8/test/es5conform/testcfg.py108
-rw-r--r--deps/v8/test/mjsunit/arguments-enum.js14
-rw-r--r--deps/v8/test/mjsunit/array-constructor.js119
-rw-r--r--deps/v8/test/mjsunit/mjsunit.status1
-rw-r--r--deps/v8/test/mjsunit/testcfg.py3
-rw-r--r--deps/v8/test/mjsunit/third_party/array-splice-webkit.js62
-rw-r--r--deps/v8/test/mjsunit/third_party/object-keys.js66
-rw-r--r--deps/v8/test/mjsunit/third_party/regexp-pcre.js (renamed from deps/v8/test/mjsunit/regexp-pcre.js)0
-rw-r--r--deps/v8/test/mozilla/mozilla.status7
-rw-r--r--deps/v8/tools/gyp/v8.gyp2
-rwxr-xr-xdeps/v8/tools/run-valgrind.py2
-rw-r--r--deps/v8/tools/v8.xcodeproj/project.pbxproj10
-rw-r--r--deps/v8/tools/visual_studio/v8_base.vcproj8
-rw-r--r--deps/v8/tools/visual_studio/v8_base_arm.vcproj8
-rw-r--r--deps/v8/tools/visual_studio/v8_base_x64.vcproj8
-rw-r--r--deps/v8/tools/visual_studio/v8_cctest.vcproj4
-rw-r--r--deps/v8/tools/visual_studio/v8_cctest_arm.vcproj4
-rw-r--r--deps/v8/tools/visual_studio/v8_cctest_x64.vcproj4
66 files changed, 2564 insertions, 569 deletions
diff --git a/deps/v8/AUTHORS b/deps/v8/AUTHORS
index 5c5ae4e1b8..de8cabb0b1 100644
--- a/deps/v8/AUTHORS
+++ b/deps/v8/AUTHORS
@@ -10,6 +10,7 @@ Alexandre Vassalotti <avassalotti@gmail.com>
Craig Schlenter <craig.schlenter@gmail.com>
Daniel Andersson <kodandersson@gmail.com>
Daniel James <dnljms@gmail.com>
+Jan de Mooij <jandemooij@gmail.com>
Jay Freeman <saurik@saurik.com>
Joel Stanley <joel.stan@gmail.com>
Matt Hanselman <mjhanselman@gmail.com>
diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog
index 009296cb44..8c7459168d 100644
--- a/deps/v8/ChangeLog
+++ b/deps/v8/ChangeLog
@@ -1,3 +1,27 @@
+2009-09-23: Version 1.3.13
+
+ Fixed uninitialized memory problem.
+
+ Improved heap profiler support.
+
+
+2009-09-22: Version 1.3.12
+
+ Changed behavior of |function|.toString() on built-in functions to
+ be compatible with other implementations. Patch by Jan de Mooij.
+
+ Added Object::IsDirty in the API.
+
+ Optimized array construction; it is now handled purely in native
+ code.
+
+ [ES5] Made properties of the arguments array enumerable.
+
+ [ES5] Added test suite adapter for the es5conform test suite.
+
+ [ES5] Added Object.keys function.
+
+
2009-09-15: Version 1.3.11
Fixed crash in error reporting during bootstrapping.
diff --git a/deps/v8/LICENSE b/deps/v8/LICENSE
index 553cf4755f..d2862b4ee8 100644
--- a/deps/v8/LICENSE
+++ b/deps/v8/LICENSE
@@ -2,10 +2,15 @@ This license applies to all parts of V8 that are not externally
maintained libraries. The externally maintained libraries used by V8
are:
- - PCRE test suite, located in test/mjsunit/regexp-pcre.js. This is
- based on the test suite from PCRE-7.3, which is copyrighted by the
- University of Cambridge and Google, Inc. The copyright notice and
- license are embedded in regexp-pcre.js.
+ - PCRE test suite, located in
+ test/mjsunit/third_party/regexp-pcre.js. This is based on the
+ test suite from PCRE-7.3, which is copyrighted by the University
+ of Cambridge and Google, Inc. The copyright notice and license
+ are embedded in regexp-pcre.js.
+
+ - Layout tests, located in test/mjsunit/third_party. These are
+ based on layout tests from webkit.org which are copyrighted by
+ Apple Computer, Inc. and released under a 3-clause BSD license.
- Dtoa, located under third_party/dtoa. This code is copyrighted by
David M. Gay and released under an MIT license.
diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h
index 24dc6d13f7..1a3177bb0d 100644
--- a/deps/v8/include/v8.h
+++ b/deps/v8/include/v8.h
@@ -1238,6 +1238,15 @@ class V8EXPORT Object : public Value {
bool SetHiddenValue(Handle<String> key, Handle<Value> value);
Local<Value> GetHiddenValue(Handle<String> key);
bool DeleteHiddenValue(Handle<String> key);
+
+ /**
+ * Returns true if this is an instance of an api function (one
+ * created from a function created from a function template) and has
+ * been modified since it was created. Note that this method is
+ * conservative and may return true for objects that haven't actually
+ * been modified.
+ */
+ bool IsDirty();
/**
* Clone this object with a fast but shallow copy. Values will point
@@ -1537,9 +1546,9 @@ enum AccessType {
/**
* Returns true if cross-context access should be allowed to the named
- * property with the given key on the global object.
+ * property with the given key on the host object.
*/
-typedef bool (*NamedSecurityCallback)(Local<Object> global,
+typedef bool (*NamedSecurityCallback)(Local<Object> host,
Local<Value> key,
AccessType type,
Local<Value> data);
@@ -1547,9 +1556,9 @@ typedef bool (*NamedSecurityCallback)(Local<Object> global,
/**
* Returns true if cross-context access should be allowed to the indexed
- * property with the given index on the global object.
+ * property with the given index on the host object.
*/
-typedef bool (*IndexedSecurityCallback)(Local<Object> global,
+typedef bool (*IndexedSecurityCallback)(Local<Object> host,
uint32_t index,
AccessType type,
Local<Value> data);
diff --git a/deps/v8/src/SConscript b/deps/v8/src/SConscript
index a1cbf1ba29..423064782a 100755
--- a/deps/v8/src/SConscript
+++ b/deps/v8/src/SConscript
@@ -42,14 +42,15 @@ SOURCES = {
'debug.cc', 'debug-agent.cc', 'disassembler.cc', 'execution.cc',
'factory.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', 'objects.cc', 'oprofile-agent.cc',
- 'parser.cc', 'property.cc', 'regexp-macro-assembler.cc',
- 'regexp-macro-assembler-irregexp.cc', 'regexp-stack.cc',
- 'register-allocator.cc', 'rewriter.cc', 'runtime.cc', 'scanner.cc',
- 'scopeinfo.cc', 'scopes.cc', 'serialize.cc', 'snapshot-common.cc',
- 'spaces.cc', 'string-stream.cc', 'stub-cache.cc', 'token.cc', 'top.cc',
+ 'hashmap.cc', 'heap.cc', 'heap-profiler.cc', 'ic.cc',
+ 'interpreter-irregexp.cc', 'jsregexp.cc', 'jump-target.cc',
+ 'log.cc', 'log-utils.cc', 'mark-compact.cc', 'messages.cc',
+ 'objects.cc', 'oprofile-agent.cc', 'parser.cc', 'property.cc',
+ 'regexp-macro-assembler.cc', 'regexp-macro-assembler-irregexp.cc',
+ 'regexp-stack.cc', 'register-allocator.cc', 'rewriter.cc',
+ 'runtime.cc', 'scanner.cc', 'scopeinfo.cc', 'scopes.cc',
+ 'serialize.cc', 'snapshot-common.cc', 'spaces.cc',
+ 'string-stream.cc', 'stub-cache.cc', 'token.cc', 'top.cc',
'unicode.cc', 'usage-analyzer.cc', 'utils.cc', 'v8-counters.cc',
'v8.cc', 'v8threads.cc', 'variables.cc', 'version.cc',
'virtual-frame.cc', 'zone.cc'
diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc
index 052e875169..eaa4f5a45e 100644
--- a/deps/v8/src/api.cc
+++ b/deps/v8/src/api.cc
@@ -1191,6 +1191,7 @@ v8::TryCatch::TryCatch()
exception_(i::Heap::the_hole_value()),
message_(i::Smi::FromInt(0)),
is_verbose_(false),
+ can_continue_(true),
capture_message_(true),
js_handler_(NULL) {
i::Top::RegisterTryCatchHandler(this);
@@ -1988,7 +1989,8 @@ Local<Array> v8::Object::GetPropertyNames() {
ENTER_V8;
v8::HandleScope scope;
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
- i::Handle<i::FixedArray> value = i::GetKeysInFixedArrayFor(self);
+ i::Handle<i::FixedArray> value =
+ i::GetKeysInFixedArrayFor(self, i::INCLUDE_PROTOS);
// Because we use caching to speed up enumeration it is important
// to never change the result of the basic enumeration function so
// we clone the result.
@@ -2155,6 +2157,11 @@ void v8::Object::TurnOnAccessCheck() {
}
+bool v8::Object::IsDirty() {
+ return Utils::OpenHandle(this)->IsDirty();
+}
+
+
Local<v8::Object> v8::Object::Clone() {
ON_BAILOUT("v8::Object::Clone()", return Local<Object>());
ENTER_V8;
diff --git a/deps/v8/src/arm/builtins-arm.cc b/deps/v8/src/arm/builtins-arm.cc
index 920110f92e..cdea1cbf6d 100644
--- a/deps/v8/src/arm/builtins-arm.cc
+++ b/deps/v8/src/arm/builtins-arm.cc
@@ -51,6 +51,22 @@ void Builtins::Generate_Adaptor(MacroAssembler* masm, CFunctionId id) {
}
+void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
+ // Just jump to the generic array code.
+ Code* code = Builtins::builtin(Builtins::ArrayCodeGeneric);
+ Handle<Code> array_code(code);
+ __ Jump(array_code, RelocInfo::CODE_TARGET);
+}
+
+
+void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
+ // Just jump to the generic construct code.
+ Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
+ Handle<Code> generic_construct_stub(code);
+ __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
+}
+
+
void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : number of arguments
diff --git a/deps/v8/src/arm/codegen-arm.cc b/deps/v8/src/arm/codegen-arm.cc
index 9ef879a5f5..477ea0519b 100644
--- a/deps/v8/src/arm/codegen-arm.cc
+++ b/deps/v8/src/arm/codegen-arm.cc
@@ -4335,7 +4335,7 @@ static void CountLeadingZeros(
Register source,
Register scratch,
Register zeros) {
-#ifdef __ARM_ARCH_5__
+#ifdef CAN_USE_ARMV5_INSTRUCTIONS
__ clz(zeros, source); // This instruction is only supported after ARM5.
#else
__ mov(zeros, Operand(0));
diff --git a/deps/v8/src/arm/constants-arm.h b/deps/v8/src/arm/constants-arm.h
index 2f2b709508..6bd0d00804 100644
--- a/deps/v8/src/arm/constants-arm.h
+++ b/deps/v8/src/arm/constants-arm.h
@@ -43,10 +43,30 @@
# define USE_THUMB_INTERWORK 1
#endif
+#if defined(__ARM_ARCH_5T__) || \
+ defined(__ARM_ARCH_5TE__) || \
+ defined(__ARM_ARCH_6__) || \
+ defined(__ARM_ARCH_7A__) || \
+ defined(__ARM_ARCH_7__)
+# define CAN_USE_ARMV5_INSTRUCTIONS 1
+# define CAN_USE_THUMB_INSTRUCTIONS 1
+#endif
+
+#if defined(__ARM_ARCH_6__) || \
+ defined(__ARM_ARCH_7A__) || \
+ defined(__ARM_ARCH_7__)
+# define CAN_USE_ARMV6_INSTRUCTIONS 1
+#endif
+
+#if defined(__ARM_ARCH_7A__) || \
+ defined(__ARM_ARCH_7__)
+# define CAN_USE_ARMV7_INSTRUCTIONS 1
+#endif
+
// Simulator should support ARM5 instructions.
#if !defined(__arm__)
-# define __ARM_ARCH_5__ 1
-# define __ARM_ARCH_5T__ 1
+# define CAN_USE_ARMV5_INSTRUCTIONS 1
+# define CAN_USE_THUMB_INSTRUCTIONS 1
#endif
namespace assembler {
diff --git a/deps/v8/src/arm/macro-assembler-arm.cc b/deps/v8/src/arm/macro-assembler-arm.cc
index 8e1eda9c99..6dd9b8faab 100644
--- a/deps/v8/src/arm/macro-assembler-arm.cc
+++ b/deps/v8/src/arm/macro-assembler-arm.cc
@@ -52,21 +52,15 @@ MacroAssembler::MacroAssembler(void* buffer, int size)
// We do not support thumb inter-working with an arm architecture not supporting
-// the blx instruction (below v5t)
-#if defined(USE_THUMB_INTERWORK)
-#if !defined(__ARM_ARCH_5T__) && \
- !defined(__ARM_ARCH_5TE__) && \
- !defined(__ARM_ARCH_6__) && \
- !defined(__ARM_ARCH_7A__) && \
- !defined(__ARM_ARCH_7__)
-// add tests for other versions above v5t as required
-#error "for thumb inter-working we require architecture v5t or above"
-#endif
+// the blx instruction (below v5t). If you know what CPU you are compiling for
+// you can use -march=armv7 or similar.
+#if defined(USE_THUMB_INTERWORK) && !defined(CAN_USE_THUMB_INSTRUCTIONS)
+# error "For thumb inter-working we require an architecture which supports blx"
#endif
// Using blx may yield better code, so use it when required or when available
-#if defined(USE_THUMB_INTERWORK) || defined(__ARM_ARCH_5__)
+#if defined(USE_THUMB_INTERWORK) || defined(CAN_USE_ARMV5_INSTRUCTIONS)
#define USE_BLX 1
#endif
diff --git a/deps/v8/src/bootstrapper.cc b/deps/v8/src/bootstrapper.cc
index c1daa57b1f..5f38485ed7 100644
--- a/deps/v8/src/bootstrapper.cc
+++ b/deps/v8/src/bootstrapper.cc
@@ -654,6 +654,8 @@ void Genesis::CreateRoots(v8::Handle<v8::ObjectTemplate> global_template,
InstallFunction(global, "Array", JS_ARRAY_TYPE, JSArray::kSize,
Top::initial_object_prototype(), Builtins::ArrayCode,
true);
+ array_function->shared()->set_construct_stub(
+ Builtins::builtin(Builtins::ArrayConstructCode));
array_function->shared()->DontAdaptArguments();
// This seems a bit hackish, but we need to make sure Array.length
@@ -1471,7 +1473,7 @@ void Genesis::MakeFunctionInstancePrototypeWritable() {
HandleScope scope;
Handle<DescriptorArray> function_map_descriptors =
- ComputeFunctionInstanceDescriptor(false, true);
+ ComputeFunctionInstanceDescriptor(false);
Handle<Map> fm = Factory::CopyMapDropDescriptors(Top::function_map());
fm->set_instance_descriptors(*function_map_descriptors);
Top::context()->global_context()->set_function_map(*fm);
diff --git a/deps/v8/src/builtins.cc b/deps/v8/src/builtins.cc
index 195fe54bef..5fe4ba9a02 100644
--- a/deps/v8/src/builtins.cc
+++ b/deps/v8/src/builtins.cc
@@ -135,7 +135,9 @@ BUILTIN(EmptyFunction) {
BUILTIN_END
-BUILTIN(ArrayCode) {
+BUILTIN(ArrayCodeGeneric) {
+ Counters::array_function_runtime.Increment();
+
JSArray* array;
if (CalledAsConstructor()) {
array = JSArray::cast(*receiver);
@@ -166,7 +168,7 @@ BUILTIN(ArrayCode) {
// Take the argument as the length.
obj = array->Initialize(0);
if (obj->IsFailure()) return obj;
- if (args.length() == 2) return array->SetElementsLength(args[1]);
+ return array->SetElementsLength(args[1]);
}
// Optimize the case where there are no parameters passed.
diff --git a/deps/v8/src/builtins.h b/deps/v8/src/builtins.h
index 8df767a925..141d5b7a58 100644
--- a/deps/v8/src/builtins.h
+++ b/deps/v8/src/builtins.h
@@ -37,7 +37,7 @@ namespace internal {
\
V(EmptyFunction) \
\
- V(ArrayCode) \
+ V(ArrayCodeGeneric) \
\
V(ArrayPush) \
V(ArrayPop) \
@@ -83,8 +83,10 @@ namespace internal {
\
/* Uses KeyedLoadIC_Initialize; must be after in list. */ \
V(FunctionCall, BUILTIN, UNINITIALIZED) \
- V(FunctionApply, BUILTIN, UNINITIALIZED)
-
+ V(FunctionApply, BUILTIN, UNINITIALIZED) \
+ \
+ V(ArrayCode, BUILTIN, UNINITIALIZED) \
+ V(ArrayConstructCode, BUILTIN, UNINITIALIZED)
#ifdef ENABLE_DEBUGGER_SUPPORT
// Define list of builtins used by the debugger implemented in assembly.
@@ -217,6 +219,9 @@ class Builtins : public AllStatic {
static void Generate_FunctionCall(MacroAssembler* masm);
static void Generate_FunctionApply(MacroAssembler* masm);
+
+ static void Generate_ArrayCode(MacroAssembler* masm);
+ static void Generate_ArrayConstructCode(MacroAssembler* masm);
};
} } // namespace v8::internal
diff --git a/deps/v8/src/handles.cc b/deps/v8/src/handles.cc
index fae006a4d0..931e3b9bf0 100644
--- a/deps/v8/src/handles.cc
+++ b/deps/v8/src/handles.cc
@@ -527,55 +527,53 @@ v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSObject> receiver,
}
-Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object) {
+Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
+ KeyCollectionType type) {
Handle<FixedArray> content = Factory::empty_fixed_array();
- JSObject* arguments_boilerplate =
- Top::context()->global_context()->arguments_boilerplate();
- JSFunction* arguments_function =
- JSFunction::cast(arguments_boilerplate->map()->constructor());
- bool allow_enumeration = (object->map()->constructor() != arguments_function);
-
// Only collect keys if access is permitted.
- if (allow_enumeration) {
- for (Handle<Object> p = object;
- *p != Heap::null_value();
- p = Handle<Object>(p->GetPrototype())) {
- Handle<JSObject> current(JSObject::cast(*p));
-
- // Check access rights if required.
- if (current->IsAccessCheckNeeded() &&
- !Top::MayNamedAccess(*current, Heap::undefined_value(),
- v8::ACCESS_KEYS)) {
- Top::ReportFailedAccessCheck(*current, v8::ACCESS_KEYS);
- break;
- }
+ for (Handle<Object> p = object;
+ *p != Heap::null_value();
+ p = Handle<Object>(p->GetPrototype())) {
+ Handle<JSObject> current(JSObject::cast(*p));
+
+ // Check access rights if required.
+ if (current->IsAccessCheckNeeded() &&
+ !Top::MayNamedAccess(*current, Heap::undefined_value(),
+ v8::ACCESS_KEYS)) {
+ Top::ReportFailedAccessCheck(*current, v8::ACCESS_KEYS);
+ break;
+ }
- // Compute the element keys.
- Handle<FixedArray> element_keys =
- Factory::NewFixedArray(current->NumberOfEnumElements());
- current->GetEnumElementKeys(*element_keys);
- content = UnionOfKeys(content, element_keys);
-
- // Add the element keys from the interceptor.
- if (current->HasIndexedInterceptor()) {
- v8::Handle<v8::Array> result =
- GetKeysForIndexedInterceptor(object, current);
- if (!result.IsEmpty())
- content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
- }
+ // Compute the element keys.
+ Handle<FixedArray> element_keys =
+ Factory::NewFixedArray(current->NumberOfEnumElements());
+ current->GetEnumElementKeys(*element_keys);
+ content = UnionOfKeys(content, element_keys);
+
+ // Add the element keys from the interceptor.
+ if (current->HasIndexedInterceptor()) {
+ v8::Handle<v8::Array> result =
+ GetKeysForIndexedInterceptor(object, current);
+ if (!result.IsEmpty())
+ content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
+ }
- // Compute the property keys.
- content = UnionOfKeys(content, GetEnumPropertyKeys(current));
+ // Compute the property keys.
+ content = UnionOfKeys(content, GetEnumPropertyKeys(current));
- // Add the property keys from the interceptor.
- if (current->HasNamedInterceptor()) {
- v8::Handle<v8::Array> result =
- GetKeysForNamedInterceptor(object, current);
- if (!result.IsEmpty())
- content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
- }
+ // Add the property keys from the interceptor.
+ if (current->HasNamedInterceptor()) {
+ v8::Handle<v8::Array> result =
+ GetKeysForNamedInterceptor(object, current);
+ if (!result.IsEmpty())
+ content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result));
}
+
+ // If we only want local properties we bail out after the first
+ // iteration.
+ if (type == LOCAL_ONLY)
+ break;
}
return content;
}
@@ -583,7 +581,8 @@ Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object) {
Handle<JSArray> GetKeysFor(Handle<JSObject> object) {
Counters::for_in.Increment();
- Handle<FixedArray> elements = GetKeysInFixedArrayFor(object);
+ Handle<FixedArray> elements = GetKeysInFixedArrayFor(object,
+ INCLUDE_PROTOS);
return Factory::NewJSArrayWithElements(elements);
}
diff --git a/deps/v8/src/handles.h b/deps/v8/src/handles.h
index 847aebb3b2..5d574657c5 100644
--- a/deps/v8/src/handles.h
+++ b/deps/v8/src/handles.h
@@ -265,9 +265,13 @@ v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSObject> receiver,
Handle<JSObject> object);
v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSObject> receiver,
Handle<JSObject> object);
+
+enum KeyCollectionType { LOCAL_ONLY, INCLUDE_PROTOS };
+
// Computes the enumerable keys for a JSObject. Used for implementing
// "for (n in object) { }".
-Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object);
+Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object,
+ KeyCollectionType type);
Handle<JSArray> GetKeysFor(Handle<JSObject> object);
Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object);
diff --git a/deps/v8/src/heap-profiler.cc b/deps/v8/src/heap-profiler.cc
new file mode 100644
index 0000000000..c1122c4b79
--- /dev/null
+++ b/deps/v8/src/heap-profiler.cc
@@ -0,0 +1,548 @@
+// 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 "heap-profiler.h"
+#include "string-stream.h"
+
+namespace v8 {
+namespace internal {
+
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+namespace {
+
+// Clusterizer is a set of helper functions for converting
+// object references into clusters.
+class Clusterizer : public AllStatic {
+ public:
+ static JSObjectsCluster Clusterize(HeapObject* obj) {
+ return Clusterize(obj, true);
+ }
+ static void InsertIntoTree(JSObjectsClusterTree* tree,
+ HeapObject* obj, bool fine_grain);
+ static void InsertReferenceIntoTree(JSObjectsClusterTree* tree,
+ const JSObjectsCluster& cluster) {
+ InsertIntoTree(tree, cluster, 0);
+ }
+
+ private:
+ static JSObjectsCluster Clusterize(HeapObject* obj, bool fine_grain);
+ static int CalculateNetworkSize(JSObject* obj);
+ static int GetObjectSize(HeapObject* obj) {
+ return obj->IsJSObject() ?
+ CalculateNetworkSize(JSObject::cast(obj)) : obj->Size();
+ }
+ static void InsertIntoTree(JSObjectsClusterTree* tree,
+ const JSObjectsCluster& cluster, int size);
+};
+
+
+JSObjectsCluster Clusterizer::Clusterize(HeapObject* obj, bool fine_grain) {
+ if (obj->IsJSObject()) {
+ JSObject* js_obj = JSObject::cast(obj);
+ String* constructor = JSObject::cast(js_obj)->constructor_name();
+ // Differentiate Array, Function, and Object instances.
+ if (fine_grain && (constructor == Heap::Object_symbol() ||
+ constructor == Heap::Array_symbol() ||
+ constructor == Heap::function_class_symbol())) {
+ return JSObjectsCluster(constructor, obj);
+ } else {
+ return JSObjectsCluster(constructor);
+ }
+ } else if (obj->IsString()) {
+ return JSObjectsCluster(Heap::String_symbol());
+ }
+ return JSObjectsCluster();
+}
+
+
+void Clusterizer::InsertIntoTree(JSObjectsClusterTree* tree,
+ HeapObject* obj, bool fine_grain) {
+ JSObjectsCluster cluster = Clusterize(obj, fine_grain);
+ if (cluster.is_null()) return;
+ InsertIntoTree(tree, cluster, GetObjectSize(obj));
+}
+
+
+void Clusterizer::InsertIntoTree(JSObjectsClusterTree* tree,
+ const JSObjectsCluster& cluster, int size) {
+ JSObjectsClusterTree::Locator loc;
+ tree->Insert(cluster, &loc);
+ NumberAndSizeInfo number_and_size = loc.value();
+ number_and_size.increment_number(1);
+ number_and_size.increment_bytes(size);
+ loc.set_value(number_and_size);
+}
+
+
+int Clusterizer::CalculateNetworkSize(JSObject* obj) {
+ int size = obj->Size();
+ // If 'properties' and 'elements' are non-empty (thus, non-shared),
+ // take their size into account.
+ if (FixedArray::cast(obj->properties())->length() != 0) {
+ size += obj->properties()->Size();
+ }
+ if (FixedArray::cast(obj->elements())->length() != 0) {
+ size += obj->elements()->Size();
+ }
+ return size;
+}
+
+
+// A helper class for recording back references.
+class ReferencesExtractor : public ObjectVisitor {
+ public:
+ ReferencesExtractor(const JSObjectsCluster& cluster,
+ RetainerHeapProfile* profile)
+ : cluster_(cluster),
+ profile_(profile),
+ inside_array_(false) {
+ }
+
+ void VisitPointer(Object** o) {
+ if ((*o)->IsJSObject() || (*o)->IsString()) {
+ profile_->StoreReference(cluster_, HeapObject::cast(*o));
+ } else if ((*o)->IsFixedArray() && !inside_array_) {
+ // Traverse one level deep for data members that are fixed arrays.
+ // This covers the case of 'elements' and 'properties' of JSObject,
+ // and function contexts.
+ inside_array_ = true;
+ FixedArray::cast(*o)->Iterate(this);
+ inside_array_ = false;
+ }
+ }
+
+ void VisitPointers(Object** start, Object** end) {
+ for (Object** p = start; p < end; p++) VisitPointer(p);
+ }
+
+ private:
+ const JSObjectsCluster& cluster_;
+ RetainerHeapProfile* profile_;
+ bool inside_array_;
+};
+
+
+// A printer interface implementation for the Retainers profile.
+class RetainersPrinter : public RetainerHeapProfile::Printer {
+ public:
+ void PrintRetainers(const JSObjectsCluster& cluster,
+ const StringStream& retainers) {
+ HeapStringAllocator allocator;
+ StringStream stream(&allocator);
+ cluster.Print(&stream);
+ LOG(HeapSampleJSRetainersEvent(
+ *(stream.ToCString()), *(retainers.ToCString())));
+ }
+};
+
+
+class RetainerTreePrinter BASE_EMBEDDED {
+ public:
+ explicit RetainerTreePrinter(StringStream* stream) : stream_(stream) {}
+ void Call(const JSObjectsCluster& cluster,
+ const NumberAndSizeInfo& number_and_size) {
+ Print(stream_, cluster, number_and_size);
+ }
+ static void Print(StringStream* stream,
+ const JSObjectsCluster& cluster,
+ const NumberAndSizeInfo& numNNber_and_size);
+
+ private:
+ StringStream* stream_;
+};
+
+
+void RetainerTreePrinter::Print(StringStream* stream,
+ const JSObjectsCluster& cluster,
+ const NumberAndSizeInfo& number_and_size) {
+ stream->Put(',');
+ cluster.Print(stream);
+ stream->Add(";%d", number_and_size.number());
+}
+
+
+} // namespace
+
+
+const JSObjectsClusterTreeConfig::Key JSObjectsClusterTreeConfig::kNoKey;
+const JSObjectsClusterTreeConfig::Value JSObjectsClusterTreeConfig::kNoValue;
+
+
+ConstructorHeapProfile::ConstructorHeapProfile()
+ : zscope_(DELETE_ON_EXIT) {
+}
+
+
+void ConstructorHeapProfile::Call(const JSObjectsCluster& cluster,
+ const NumberAndSizeInfo& number_and_size) {
+ HeapStringAllocator allocator;
+ StringStream stream(&allocator);
+ cluster.Print(&stream);
+ LOG(HeapSampleJSConstructorEvent(*(stream.ToCString()),
+ number_and_size.number(),
+ number_and_size.bytes()));
+}
+
+
+void ConstructorHeapProfile::CollectStats(HeapObject* obj) {
+ Clusterizer::InsertIntoTree(&js_objects_info_tree_, obj, false);
+}
+
+
+void ConstructorHeapProfile::PrintStats() {
+ js_objects_info_tree_.ForEach(this);
+}
+
+
+void JSObjectsCluster::Print(StringStream* accumulator) const {
+ ASSERT(!is_null());
+ if (constructor_ == FromSpecialCase(ROOTS)) {
+ accumulator->Add("(roots)");
+ } else if (constructor_ == FromSpecialCase(GLOBAL_PROPERTY)) {
+ accumulator->Add("(global property)");
+ } else {
+ SmartPointer<char> s_name(
+ constructor_->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL));
+ accumulator->Add("%s", (*s_name)[0] != '\0' ? *s_name : "(anonymous)");
+ if (instance_ != NULL) {
+ accumulator->Add(":%p", static_cast<void*>(instance_));
+ }
+ }
+}
+
+
+void JSObjectsCluster::DebugPrint(StringStream* accumulator) const {
+ if (!is_null()) {
+ Print(accumulator);
+ } else {
+ accumulator->Add("(null cluster)");
+ }
+}
+
+
+inline ClustersCoarser::ClusterBackRefs::ClusterBackRefs(
+ const JSObjectsCluster& cluster_)
+ : cluster(cluster_), refs(kInitialBackrefsListCapacity) {
+}
+
+
+inline ClustersCoarser::ClusterBackRefs::ClusterBackRefs(
+ const ClustersCoarser::ClusterBackRefs& src)
+ : cluster(src.cluster), refs(src.refs.capacity()) {
+ refs.AddAll(src.refs);
+}
+
+
+inline ClustersCoarser::ClusterBackRefs&
+ ClustersCoarser::ClusterBackRefs::operator=(
+ const ClustersCoarser::ClusterBackRefs& src) {
+ if (this == &src) return *this;
+ cluster = src.cluster;
+ refs.Clear();
+ refs.AddAll(src.refs);
+ return *this;
+}
+
+
+inline int ClustersCoarser::ClusterBackRefs::Compare(
+ const ClustersCoarser::ClusterBackRefs& a,
+ const ClustersCoarser::ClusterBackRefs& b) {
+ int cmp = JSObjectsCluster::CompareConstructors(a.cluster, b.cluster);
+ if (cmp != 0) return cmp;
+ if (a.refs.length() < b.refs.length()) return -1;
+ if (a.refs.length() > b.refs.length()) return 1;
+ for (int i = 0; i < a.refs.length(); ++i) {
+ int cmp = JSObjectsCluster::Compare(a.refs[i], b.refs[i]);
+ if (cmp != 0) return cmp;
+ }
+ return 0;
+}
+
+
+ClustersCoarser::ClustersCoarser()
+ : zscope_(DELETE_ON_EXIT),
+ sim_list_(ClustersCoarser::kInitialSimilarityListCapacity),
+ current_pair_(NULL) {
+}
+
+
+void ClustersCoarser::Call(const JSObjectsCluster& cluster,
+ JSObjectsClusterTree* tree) {
+ if (!cluster.can_be_coarsed()) return;
+ ClusterBackRefs pair(cluster);
+ ASSERT(current_pair_ == NULL);
+ current_pair_ = &pair;
+ current_set_ = new JSObjectsRetainerTree();
+ tree->ForEach(this);
+ sim_list_.Add(pair);
+ current_pair_ = NULL;
+ current_set_ = NULL;
+}
+
+
+void ClustersCoarser::Call(const JSObjectsCluster& cluster,
+ const NumberAndSizeInfo& number_and_size) {
+ ASSERT(current_pair_ != NULL);
+ ASSERT(current_set_ != NULL);
+ JSObjectsCluster eq = GetCoarseEquivalent(cluster);
+ JSObjectsRetainerTree::Locator loc;
+ if (!eq.is_null()) {
+ if (current_set_->Find(eq, &loc)) return;
+ current_pair_->refs.Add(eq);
+ current_set_->Insert(eq, &loc);
+ } else {
+ current_pair_->refs.Add(cluster);
+ }
+}
+
+
+void ClustersCoarser::Process(JSObjectsRetainerTree* tree) {
+ int last_eq_clusters = -1;
+ for (int i = 0; i < kMaxPassesCount; ++i) {
+ sim_list_.Clear();
+ const int curr_eq_clusters = DoProcess(tree);
+ // If no new cluster equivalents discovered, abort processing.
+ if (last_eq_clusters == curr_eq_clusters) break;
+ last_eq_clusters = curr_eq_clusters;
+ }
+}
+
+
+int ClustersCoarser::DoProcess(JSObjectsRetainerTree* tree) {
+ tree->ForEach(this);
+ // To sort similarity list properly, references list of a cluster is
+ // required to be sorted, thus 'O1 <- A, B' and 'O2 <- B, A' would
+ // be considered equivalent. But we don't sort them explicitly
+ // because we know that they come from a splay tree traversal, so
+ // they are already sorted.
+ sim_list_.Sort(ClusterBackRefsCmp);
+ return FillEqualityTree();
+}
+
+
+JSObjectsCluster ClustersCoarser::GetCoarseEquivalent(
+ const JSObjectsCluster& cluster) {
+ if (!cluster.can_be_coarsed()) return JSObjectsCluster();
+ EqualityTree::Locator loc;
+ return eq_tree_.Find(cluster, &loc) ? loc.value() : JSObjectsCluster();
+}
+
+
+bool ClustersCoarser::HasAnEquivalent(const JSObjectsCluster& cluster) {
+ // Return true for coarsible clusters that have a non-identical equivalent.
+ return cluster.can_be_coarsed() &&
+ JSObjectsCluster::Compare(cluster, GetCoarseEquivalent(cluster)) != 0;
+}
+
+
+int ClustersCoarser::FillEqualityTree() {
+ int eq_clusters_count = 0;
+ int eq_to = 0;
+ bool first_added = false;
+ for (int i = 1; i < sim_list_.length(); ++i) {
+ if (ClusterBackRefs::Compare(sim_list_[i], sim_list_[eq_to]) == 0) {
+ EqualityTree::Locator loc;
+ if (!first_added) {
+ // Add self-equivalence, if we have more than one item in this
+ // equivalence class.
+ eq_tree_.Insert(sim_list_[eq_to].cluster, &loc);
+ loc.set_value(sim_list_[eq_to].cluster);
+ first_added = true;
+ }
+ eq_tree_.Insert(sim_list_[i].cluster, &loc);
+ loc.set_value(sim_list_[eq_to].cluster);
+ ++eq_clusters_count;
+ } else {
+ eq_to = i;
+ first_added = false;
+ }
+ }
+ return eq_clusters_count;
+}
+
+
+const JSObjectsCluster ClustersCoarser::ClusterEqualityConfig::kNoKey;
+const JSObjectsCluster ClustersCoarser::ClusterEqualityConfig::kNoValue;
+const JSObjectsRetainerTreeConfig::Key JSObjectsRetainerTreeConfig::kNoKey;
+const JSObjectsRetainerTreeConfig::Value JSObjectsRetainerTreeConfig::kNoValue =
+ NULL;
+
+
+RetainerHeapProfile::RetainerHeapProfile()
+ : zscope_(DELETE_ON_EXIT),
+ coarse_cluster_tree_(NULL),
+ current_printer_(NULL),
+ current_stream_(NULL) {
+ JSObjectsCluster roots(JSObjectsCluster::ROOTS);
+ ReferencesExtractor extractor(roots, this);
+ Heap::IterateRoots(&extractor);
+}
+
+
+void RetainerHeapProfile::StoreReference(const JSObjectsCluster& cluster,
+ HeapObject* ref) {
+ JSObjectsCluster ref_cluster = Clusterizer::Clusterize(ref);
+ JSObjectsRetainerTree::Locator ref_loc;
+ if (retainers_tree_.Insert(ref_cluster, &ref_loc)) {
+ ref_loc.set_value(new JSObjectsClusterTree());
+ }
+ JSObjectsClusterTree* referenced_by = ref_loc.value();
+ Clusterizer::InsertReferenceIntoTree(referenced_by, cluster);
+}
+
+
+void RetainerHeapProfile::CollectStats(HeapObject* obj) {
+ if (obj->IsJSObject()) {
+ const JSObjectsCluster cluster = Clusterizer::Clusterize(obj);
+ ReferencesExtractor extractor(cluster, this);
+ obj->Iterate(&extractor);
+ } else if (obj->IsJSGlobalPropertyCell()) {
+ JSObjectsCluster global_prop(JSObjectsCluster::GLOBAL_PROPERTY);
+ ReferencesExtractor extractor(global_prop, this);
+ obj->Iterate(&extractor);
+ }
+}
+
+
+void RetainerHeapProfile::DebugPrintStats(
+ RetainerHeapProfile::Printer* printer) {
+ coarser_.Process(&retainers_tree_);
+ ASSERT(current_printer_ == NULL);
+ current_printer_ = printer;
+ retainers_tree_.ForEach(this);
+ current_printer_ = NULL;
+}
+
+
+void RetainerHeapProfile::PrintStats() {
+ RetainersPrinter printer;
+ DebugPrintStats(&printer);
+}
+
+
+void RetainerHeapProfile::Call(const JSObjectsCluster& cluster,
+ JSObjectsClusterTree* tree) {
+ // First level of retainer graph.
+ if (coarser_.HasAnEquivalent(cluster)) return;
+ ASSERT(current_stream_ == NULL);
+ HeapStringAllocator allocator;
+ StringStream stream(&allocator);
+ current_stream_ = &stream;
+ ASSERT(coarse_cluster_tree_ == NULL);
+ coarse_cluster_tree_ = new JSObjectsClusterTree();
+ tree->ForEach(this);
+ // Print aggregated counts and sizes.
+ RetainerTreePrinter printer(current_stream_);
+ coarse_cluster_tree_->ForEach(&printer);
+ coarse_cluster_tree_ = NULL;
+ current_printer_->PrintRetainers(cluster, stream);
+ current_stream_ = NULL;
+}
+
+
+void RetainerHeapProfile::Call(const JSObjectsCluster& cluster,
+ const NumberAndSizeInfo& number_and_size) {
+ ASSERT(coarse_cluster_tree_ != NULL);
+ ASSERT(current_stream_ != NULL);
+ JSObjectsCluster eq = coarser_.GetCoarseEquivalent(cluster);
+ if (eq.is_null()) {
+ RetainerTreePrinter::Print(current_stream_, cluster, number_and_size);
+ } else {
+ // Aggregate counts and sizes for equivalent clusters.
+ JSObjectsClusterTree::Locator loc;
+ coarse_cluster_tree_->Insert(eq, &loc);
+ NumberAndSizeInfo eq_number_and_size = loc.value();
+ eq_number_and_size.increment_number(number_and_size.number());
+ loc.set_value(eq_number_and_size);
+ }
+}
+
+
+//
+// HeapProfiler class implementation.
+//
+void HeapProfiler::CollectStats(HeapObject* obj, HistogramInfo* info) {
+ InstanceType type = obj->map()->instance_type();
+ ASSERT(0 <= type && type <= LAST_TYPE);
+ info[type].increment_number(1);
+ info[type].increment_bytes(obj->Size());
+}
+
+
+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);
+ INSTANCE_TYPE_LIST(DEF_TYPE_NAME)
+#undef DEF_TYPE_NAME
+
+ ConstructorHeapProfile js_cons_profile;
+ RetainerHeapProfile js_retainer_profile;
+ HeapIterator iterator;
+ while (iterator.has_next()) {
+ HeapObject* obj = iterator.next();
+ CollectStats(obj, info);
+ js_cons_profile.CollectStats(obj);
+ js_retainer_profile.CollectStats(obj);
+ }
+
+ // Lump all the string types together.
+ int string_number = 0;
+ int string_bytes = 0;
+#define INCREMENT_SIZE(type, size, name, camel_name) \
+ string_number += info[type].number(); \
+ string_bytes += info[type].bytes();
+ STRING_TYPE_LIST(INCREMENT_SIZE)
+#undef INCREMENT_SIZE
+ if (string_bytes > 0) {
+ LOG(HeapSampleItemEvent("STRING_TYPE", string_number, string_bytes));
+ }
+
+ for (int i = FIRST_NONSTRING_TYPE; i <= LAST_TYPE; ++i) {
+ if (info[i].bytes() > 0) {
+ LOG(HeapSampleItemEvent(info[i].name(), info[i].number(),
+ info[i].bytes()));
+ }
+ }
+
+ js_cons_profile.PrintStats();
+ js_retainer_profile.PrintStats();
+
+ LOG(HeapSampleEndEvent("Heap", "allocated"));
+}
+
+
+#endif // ENABLE_LOGGING_AND_PROFILING
+
+
+} } // namespace v8::internal
diff --git a/deps/v8/src/heap-profiler.h b/deps/v8/src/heap-profiler.h
new file mode 100644
index 0000000000..adc3da2b86
--- /dev/null
+++ b/deps/v8/src/heap-profiler.h
@@ -0,0 +1,266 @@
+// 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.
+
+#ifndef V8_HEAP_PROFILER_H_
+#define V8_HEAP_PROFILER_H_
+
+namespace v8 {
+namespace internal {
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+
+// The HeapProfiler writes data to the log files, which can be postprocessed
+// to generate .hp files for use by the GHC/Valgrind tool hp2ps.
+class HeapProfiler {
+ public:
+ // Write a single heap sample to the log file.
+ static void WriteSample();
+
+ private:
+ // Update the array info with stats from obj.
+ static void CollectStats(HeapObject* obj, HistogramInfo* info);
+};
+
+
+// JSObjectsCluster describes a group of JS objects that are
+// considered equivalent in terms of a particular profile.
+class JSObjectsCluster BASE_EMBEDDED {
+ public:
+ // These special cases are used in retainer profile.
+ enum SpecialCase {
+ ROOTS = 1,
+ GLOBAL_PROPERTY = 2
+ };
+
+ JSObjectsCluster() : constructor_(NULL), instance_(NULL) {}
+ explicit JSObjectsCluster(String* constructor)
+ : constructor_(constructor), instance_(NULL) {}
+ explicit JSObjectsCluster(SpecialCase special)
+ : constructor_(FromSpecialCase(special)), instance_(NULL) {}
+ JSObjectsCluster(String* constructor, Object* instance)
+ : constructor_(constructor), instance_(instance) {}
+
+ static int CompareConstructors(const JSObjectsCluster& a,
+ const JSObjectsCluster& b) {
+ // Strings are unique, so it is sufficient to compare their pointers.
+ return a.constructor_ == b.constructor_ ? 0
+ : (a.constructor_ < b.constructor_ ? -1 : 1);
+ }
+ static int Compare(const JSObjectsCluster& a, const JSObjectsCluster& b) {
+ // Strings are unique, so it is sufficient to compare their pointers.
+ const int cons_cmp = CompareConstructors(a, b);
+ return cons_cmp == 0 ?
+ (a.instance_ == b.instance_ ? 0 : (a.instance_ < b.instance_ ? -1 : 1))
+ : cons_cmp;
+ }
+
+ bool is_null() const { return constructor_ == NULL; }
+ bool can_be_coarsed() const { return instance_ != NULL; }
+ String* constructor() const { return constructor_; }
+
+ void Print(StringStream* accumulator) const;
+ // Allows null clusters to be printed.
+ void DebugPrint(StringStream* accumulator) const;
+
+ private:
+ static String* FromSpecialCase(SpecialCase special) {
+ // We use symbols that are illegal JS identifiers to identify special cases.
+ // Their actual value is irrelevant for us.
+ switch (special) {
+ case ROOTS: return Heap::result_symbol();
+ case GLOBAL_PROPERTY: return Heap::code_symbol();
+ default:
+ UNREACHABLE();
+ return NULL;
+ }
+ }
+
+ String* constructor_;
+ Object* instance_;
+};
+
+
+struct JSObjectsClusterTreeConfig {
+ typedef JSObjectsCluster Key;
+ typedef NumberAndSizeInfo Value;
+ static const Key kNoKey;
+ static const Value kNoValue;
+ static int Compare(const Key& a, const Key& b) {
+ return Key::Compare(a, b);
+ }
+};
+typedef ZoneSplayTree<JSObjectsClusterTreeConfig> JSObjectsClusterTree;
+
+
+// ConstructorHeapProfile is responsible for gathering and logging
+// "constructor profile" of JS objects allocated on heap.
+// It is run during garbage collection cycle, thus it doesn't need
+// to use handles.
+class ConstructorHeapProfile BASE_EMBEDDED {
+ public:
+ ConstructorHeapProfile();
+ virtual ~ConstructorHeapProfile() {}
+ void CollectStats(HeapObject* obj);
+ void PrintStats();
+ // Used by ZoneSplayTree::ForEach. Made virtual to allow overriding in tests.
+ virtual void Call(const JSObjectsCluster& cluster,
+ const NumberAndSizeInfo& number_and_size);
+
+ private:
+ ZoneScope zscope_;
+ JSObjectsClusterTree js_objects_info_tree_;
+};
+
+
+// JSObjectsRetainerTree is used to represent retainer graphs using
+// adjacency list form:
+//
+// Cluster -> (Cluster -> NumberAndSizeInfo)
+//
+// Subordinate splay trees are stored by pointer. They are zone-allocated,
+// so it isn't needed to manage their lifetime.
+//
+struct JSObjectsRetainerTreeConfig {
+ typedef JSObjectsCluster Key;
+ typedef JSObjectsClusterTree* Value;
+ static const Key kNoKey;
+ static const Value kNoValue;
+ static int Compare(const Key& a, const Key& b) {
+ return Key::Compare(a, b);
+ }
+};
+typedef ZoneSplayTree<JSObjectsRetainerTreeConfig> JSObjectsRetainerTree;
+
+
+class ClustersCoarser BASE_EMBEDDED {
+ public:
+ ClustersCoarser();
+
+ // Processes a given retainer graph.
+ void Process(JSObjectsRetainerTree* tree);
+
+ // Returns an equivalent cluster (can be the cluster itself).
+ // If the given cluster doesn't have an equivalent, returns null cluster.
+ JSObjectsCluster GetCoarseEquivalent(const JSObjectsCluster& cluster);
+ // Returns whether a cluster can be substitued with an equivalent and thus,
+ // skipped in some cases.
+ bool HasAnEquivalent(const JSObjectsCluster& cluster);
+
+ // Used by JSObjectsRetainerTree::ForEach.
+ void Call(const JSObjectsCluster& cluster, JSObjectsClusterTree* tree);
+ void Call(const JSObjectsCluster& cluster,
+ const NumberAndSizeInfo& number_and_size);
+
+ private:
+ // Stores a list of back references for a cluster.
+ struct ClusterBackRefs {
+ explicit ClusterBackRefs(const JSObjectsCluster& cluster_);
+ ClusterBackRefs(const ClusterBackRefs& src);
+ ClusterBackRefs& operator=(const ClusterBackRefs& src);
+
+ static int Compare(const ClusterBackRefs& a, const ClusterBackRefs& b);
+
+ JSObjectsCluster cluster;
+ ZoneList<JSObjectsCluster> refs;
+ };
+ typedef ZoneList<ClusterBackRefs> SimilarityList;
+
+ // A tree for storing a list of equivalents for a cluster.
+ struct ClusterEqualityConfig {
+ typedef JSObjectsCluster Key;
+ typedef JSObjectsCluster Value;
+ static const Key kNoKey;
+ static const Value kNoValue;
+ static int Compare(const Key& a, const Key& b) {
+ return Key::Compare(a, b);
+ }
+ };
+ typedef ZoneSplayTree<ClusterEqualityConfig> EqualityTree;
+
+ static int ClusterBackRefsCmp(const ClusterBackRefs* a,
+ const ClusterBackRefs* b) {
+ return ClusterBackRefs::Compare(*a, *b);
+ }
+ int DoProcess(JSObjectsRetainerTree* tree);
+ int FillEqualityTree();
+
+ static const int kInitialBackrefsListCapacity = 2;
+ static const int kInitialSimilarityListCapacity = 2000;
+ // Number of passes for finding equivalents. Limits the length of paths
+ // that can be considered equivalent.
+ static const int kMaxPassesCount = 10;
+
+ ZoneScope zscope_;
+ SimilarityList sim_list_;
+ EqualityTree eq_tree_;
+ ClusterBackRefs* current_pair_;
+ JSObjectsRetainerTree* current_set_;
+};
+
+
+// RetainerHeapProfile is responsible for gathering and logging
+// "retainer profile" of JS objects allocated on heap.
+// It is run during garbage collection cycle, thus it doesn't need
+// to use handles.
+class RetainerHeapProfile BASE_EMBEDDED {
+ public:
+ class Printer {
+ public:
+ virtual ~Printer() {}
+ virtual void PrintRetainers(const JSObjectsCluster& cluster,
+ const StringStream& retainers) = 0;
+ };
+
+ RetainerHeapProfile();
+ void CollectStats(HeapObject* obj);
+ void PrintStats();
+ void DebugPrintStats(Printer* printer);
+ void StoreReference(const JSObjectsCluster& cluster, HeapObject* ref);
+
+ private:
+ // Limit on the number of retainers to be printed per cluster.
+ static const int kMaxRetainersToPrint = 50;
+ ZoneScope zscope_;
+ JSObjectsRetainerTree retainers_tree_;
+ ClustersCoarser coarser_;
+ // TODO(mnaganov): Use some helper class to hold these state variables.
+ JSObjectsClusterTree* coarse_cluster_tree_;
+ Printer* current_printer_;
+ StringStream* current_stream_;
+ public:
+ // Used by JSObjectsRetainerTree::ForEach.
+ void Call(const JSObjectsCluster& cluster, JSObjectsClusterTree* tree);
+ void Call(const JSObjectsCluster& cluster,
+ const NumberAndSizeInfo& number_and_size);
+};
+
+
+#endif // ENABLE_LOGGING_AND_PROFILING
+
+} } // namespace v8::internal
+
+#endif // V8_HEAP_PROFILER_H_
diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc
index 949dd80c3b..1a80d64784 100644
--- a/deps/v8/src/heap.cc
+++ b/deps/v8/src/heap.cc
@@ -33,6 +33,7 @@
#include "codegen-inl.h"
#include "compilation-cache.h"
#include "debug.h"
+#include "heap-profiler.h"
#include "global-handles.h"
#include "mark-compact.h"
#include "natives.h"
@@ -636,15 +637,7 @@ static void VerifyNonPointerSpacePointers() {
HeapObjectIterator code_it(Heap::code_space());
while (code_it.has_next()) {
HeapObject* object = code_it.next();
- if (object->IsCode()) {
- Code::cast(object)->ConvertICTargetsFromAddressToObject();
- object->Iterate(&v);
- Code::cast(object)->ConvertICTargetsFromObjectToAddress();
- } else {
- // If we find non-code objects in code space (e.g., free list
- // nodes) we want to verify them as well.
- object->Iterate(&v);
- }
+ object->Iterate(&v);
}
HeapObjectIterator data_it(Heap::old_data_space());
@@ -1934,7 +1927,6 @@ Object* Heap::CreateCode(const CodeDesc& desc,
code->set_relocation_size(desc.reloc_size);
code->set_sinfo_size(sinfo_size);
code->set_flags(flags);
- code->set_ic_flag(Code::IC_TARGET_IS_ADDRESS);
// Allow self references to created code object by patching the handle to
// point to the newly allocated Code object.
if (!self_reference.is_null()) {
@@ -3544,164 +3536,6 @@ void HeapIterator::reset() {
}
-#ifdef ENABLE_LOGGING_AND_PROFILING
-namespace {
-
-// JSConstructorProfile is responsible for gathering and logging
-// "constructor profile" of JS object allocated on heap.
-// It is run during garbage collection cycle, thus it doesn't need
-// to use handles.
-class JSConstructorProfile BASE_EMBEDDED {
- public:
- JSConstructorProfile() : zscope_(DELETE_ON_EXIT) {}
- void CollectStats(HeapObject* obj);
- void PrintStats();
- // Used by ZoneSplayTree::ForEach.
- void Call(String* name, const NumberAndSizeInfo& number_and_size);
- private:
- struct TreeConfig {
- typedef String* Key;
- typedef NumberAndSizeInfo Value;
- static const Key kNoKey;
- static const Value kNoValue;
- // Strings are unique, so it is sufficient to compare their pointers.
- static int Compare(const Key& a, const Key& b) {
- return a == b ? 0 : (a < b ? -1 : 1);
- }
- };
-
- typedef ZoneSplayTree<TreeConfig> JSObjectsInfoTree;
- static int CalculateJSObjectNetworkSize(JSObject* obj);
-
- ZoneScope zscope_;
- JSObjectsInfoTree js_objects_info_tree_;
-};
-
-const JSConstructorProfile::TreeConfig::Key
- JSConstructorProfile::TreeConfig::kNoKey = NULL;
-const JSConstructorProfile::TreeConfig::Value
- JSConstructorProfile::TreeConfig::kNoValue;
-
-
-int JSConstructorProfile::CalculateJSObjectNetworkSize(JSObject* obj) {
- int size = obj->Size();
- // If 'properties' and 'elements' are non-empty (thus, non-shared),
- // take their size into account.
- if (FixedArray::cast(obj->properties())->length() != 0) {
- size += obj->properties()->Size();
- }
- if (FixedArray::cast(obj->elements())->length() != 0) {
- size += obj->elements()->Size();
- }
- return size;
-}
-
-
-void JSConstructorProfile::Call(String* name,
- const NumberAndSizeInfo& number_and_size) {
- ASSERT(name != NULL);
- SmartPointer<char> s_name(
- name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL));
- LOG(HeapSampleJSConstructorEvent(*s_name,
- number_and_size.number(),
- number_and_size.bytes()));
-}
-
-
-void JSConstructorProfile::CollectStats(HeapObject* obj) {
- String* constructor = NULL;
- int size;
- if (obj->IsString()) {
- constructor = Heap::String_symbol();
- size = obj->Size();
- } else if (obj->IsJSObject()) {
- JSObject* js_obj = JSObject::cast(obj);
- constructor = js_obj->constructor_name();
- size = CalculateJSObjectNetworkSize(js_obj);
- } else {
- return;
- }
-
- JSObjectsInfoTree::Locator loc;
- if (!js_objects_info_tree_.Find(constructor, &loc)) {
- js_objects_info_tree_.Insert(constructor, &loc);
- }
- NumberAndSizeInfo number_and_size = loc.value();
- number_and_size.increment_number(1);
- number_and_size.increment_bytes(size);
- loc.set_value(number_and_size);
-}
-
-
-void JSConstructorProfile::PrintStats() {
- js_objects_info_tree_.ForEach(this);
-}
-
-} // namespace
-#endif
-
-
-//
-// HeapProfiler class implementation.
-//
-#ifdef ENABLE_LOGGING_AND_PROFILING
-void HeapProfiler::CollectStats(HeapObject* obj, HistogramInfo* info) {
- InstanceType type = obj->map()->instance_type();
- ASSERT(0 <= type && type <= LAST_TYPE);
- info[type].increment_number(1);
- info[type].increment_bytes(obj->Size());
-}
-#endif
-
-
-#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);
- INSTANCE_TYPE_LIST(DEF_TYPE_NAME)
-#undef DEF_TYPE_NAME
-
- JSConstructorProfile js_cons_profile;
- HeapIterator iterator;
- while (iterator.has_next()) {
- HeapObject* obj = iterator.next();
- CollectStats(obj, info);
- js_cons_profile.CollectStats(obj);
- }
-
- // Lump all the string types together.
- int string_number = 0;
- int string_bytes = 0;
-#define INCREMENT_SIZE(type, size, name, camel_name) \
- string_number += info[type].number(); \
- string_bytes += info[type].bytes();
- STRING_TYPE_LIST(INCREMENT_SIZE)
-#undef INCREMENT_SIZE
- if (string_bytes > 0) {
- LOG(HeapSampleItemEvent("STRING_TYPE", string_number, string_bytes));
- }
-
- for (int i = FIRST_NONSTRING_TYPE; i <= LAST_TYPE; ++i) {
- if (info[i].bytes() > 0) {
- LOG(HeapSampleItemEvent(info[i].name(), info[i].number(),
- info[i].bytes()));
- }
- }
-
- js_cons_profile.PrintStats();
-
- LOG(HeapSampleEndEvent("Heap", "allocated"));
-}
-
-
-#endif
-
-
-
#ifdef DEBUG
static bool search_for_any_global;
@@ -3744,10 +3578,6 @@ static void MarkObjectRecursively(Object** p) {
return;
}
- if (obj->IsCode()) {
- Code::cast(obj)->ConvertICTargetsFromAddressToObject();
- }
-
// not visited yet
Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map));
@@ -3803,10 +3633,6 @@ static void UnmarkObjectRecursively(Object** p) {
obj->IterateBody(Map::cast(map_p)->instance_type(),
obj->SizeFromMap(Map::cast(map_p)),
&unmark_visitor);
-
- if (obj->IsCode()) {
- Code::cast(obj)->ConvertICTargetsFromObjectToAddress();
- }
}
diff --git a/deps/v8/src/heap.h b/deps/v8/src/heap.h
index 028dd11181..92602c8506 100644
--- a/deps/v8/src/heap.h
+++ b/deps/v8/src/heap.h
@@ -1443,20 +1443,6 @@ class DisableAssertNoAllocation {
#endif
-#ifdef ENABLE_LOGGING_AND_PROFILING
-// The HeapProfiler writes data to the log files, which can be postprocessed
-// to generate .hp files for use by the GHC/Valgrind tool hp2ps.
-class HeapProfiler {
- public:
- // Write a single heap sample to the log file.
- static void WriteSample();
-
- private:
- // Update the array info with stats from obj.
- static void CollectStats(HeapObject* obj, HistogramInfo* info);
-};
-#endif
-
// GCTracer collects and prints ONE line after each garbage collector
// invocation IFF --trace_gc is used.
diff --git a/deps/v8/src/ia32/builtins-ia32.cc b/deps/v8/src/ia32/builtins-ia32.cc
index 7793e49265..e7712df30c 100644
--- a/deps/v8/src/ia32/builtins-ia32.cc
+++ b/deps/v8/src/ia32/builtins-ia32.cc
@@ -658,6 +658,466 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
}
+// Load the built-in Array function from the current context.
+static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) {
+ // Load the global context.
+ __ mov(result, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
+ __ mov(result, FieldOperand(result, GlobalObject::kGlobalContextOffset));
+ // Load the Array function from the global context.
+ __ mov(result,
+ Operand(result, Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
+}
+
+
+// Number of empty elements to allocate for an empty array.
+static const int kPreallocatedArrayElements = 4;
+
+
+// Allocate an empty JSArray. The allocated array is put into the result
+// register. If the parameter holes is larger than zero an elements backing
+// store is allocated with this size and filled with the hole values. Otherwise
+// the elements backing store is set to the empty FixedArray.
+static void AllocateEmptyJSArray(MacroAssembler* masm,
+ Register array_function,
+ Register result,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ int holes,
+ Label* gc_required) {
+ ASSERT(holes >= 0);
+
+ // Load the initial map from the array function.
+ __ mov(scratch1, FieldOperand(array_function,
+ JSFunction::kPrototypeOrInitialMapOffset));
+
+ // Allocate the JSArray object together with space for a fixed array with the
+ // requested elements.
+ int size = JSArray::kSize;
+ if (holes > 0) {
+ size += FixedArray::SizeFor(holes);
+ }
+ __ AllocateObjectInNewSpace(size,
+ result,
+ scratch2,
+ scratch3,
+ gc_required,
+ TAG_OBJECT);
+
+ // Allocated the JSArray. Now initialize the fields except for the elements
+ // array.
+ // result: JSObject
+ // scratch1: initial map
+ // scratch2: start of next object
+ __ mov(FieldOperand(result, JSObject::kMapOffset), scratch1);
+ __ mov(FieldOperand(result, JSArray::kPropertiesOffset),
+ Factory::empty_fixed_array());
+ // Field JSArray::kElementsOffset is initialized later.
+ __ mov(FieldOperand(result, JSArray::kLengthOffset), Immediate(0));
+
+ // If no storage is requested for the elements array just set the empty
+ // fixed array.
+ if (holes == 0) {
+ __ mov(FieldOperand(result, JSArray::kElementsOffset),
+ Factory::empty_fixed_array());
+ return;
+ }
+
+ // Calculate the location of the elements array and set elements array member
+ // of the JSArray.
+ // result: JSObject
+ // scratch2: start of next object
+ __ lea(scratch1, Operand(result, JSArray::kSize));
+ __ mov(FieldOperand(result, JSArray::kElementsOffset), scratch1);
+
+ // Initialize the FixedArray and fill it with holes. FixedArray length is not
+ // stored as a smi.
+ // result: JSObject
+ // scratch1: elements array
+ // scratch2: start of next object
+ __ mov(FieldOperand(scratch1, JSObject::kMapOffset),
+ Factory::fixed_array_map());
+ __ mov(FieldOperand(scratch1, Array::kLengthOffset), Immediate(holes));
+
+ // Fill the FixedArray with the hole value. Inline the code if short.
+ // Reconsider loop unfolding if kPreallocatedArrayElements gets changed.
+ static const int kLoopUnfoldLimit = 4;
+ ASSERT(kPreallocatedArrayElements <= kLoopUnfoldLimit);
+ if (holes <= kLoopUnfoldLimit) {
+ // Use a scratch register here to have only one reloc info when unfolding
+ // the loop.
+ __ mov(scratch3, Factory::the_hole_value());
+ for (int i = 0; i < holes; i++) {
+ __ mov(FieldOperand(scratch1,
+ FixedArray::kHeaderSize + i * kPointerSize),
+ scratch3);
+ }
+ } else {
+ Label loop, entry;
+ __ jmp(&entry);
+ __ bind(&loop);
+ __ mov(Operand(scratch1, 0), Factory::the_hole_value());
+ __ add(Operand(scratch1), Immediate(kPointerSize));
+ __ bind(&entry);
+ __ cmp(scratch1, Operand(scratch2));
+ __ j(below, &loop);
+ }
+}
+
+
+// Allocate a JSArray with the number of elements stored in a register. The
+// register array_function holds the built-in Array function and the register
+// array_size holds the size of the array as a smi. The allocated array is put
+// into the result register and beginning and end of the FixedArray elements
+// storage is put into registers elements_array and elements_array_end (see
+// below for when that is not the case). If the parameter fill_with_holes is
+// true the allocated elements backing store is filled with the hole values
+// otherwise it is left uninitialized. When the backing store is filled the
+// register elements_array is scratched.
+static void AllocateJSArray(MacroAssembler* masm,
+ Register array_function, // Array function.
+ Register array_size, // As a smi.
+ Register result,
+ Register elements_array,
+ Register elements_array_end,
+ Register scratch,
+ bool fill_with_hole,
+ Label* gc_required) {
+ Label not_empty, allocated;
+
+ // Load the initial map from the array function.
+ __ mov(elements_array,
+ FieldOperand(array_function,
+ JSFunction::kPrototypeOrInitialMapOffset));
+
+ // Check whether an empty sized array is requested.
+ __ test(array_size, Operand(array_size));
+ __ j(not_zero, &not_empty);
+
+ // If an empty array is requested allocate a small elements array anyway. This
+ // keeps the code below free of special casing for the empty array.
+ int size = JSArray::kSize + FixedArray::SizeFor(kPreallocatedArrayElements);
+ __ AllocateObjectInNewSpace(size,
+ result,
+ elements_array_end,
+ scratch,
+ gc_required,
+ TAG_OBJECT);
+ __ jmp(&allocated);
+
+ // Allocate the JSArray object together with space for a FixedArray with the
+ // requested elements.
+ __ bind(&not_empty);
+ ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
+ __ AllocateObjectInNewSpace(JSArray::kSize + FixedArray::kHeaderSize,
+ times_half_pointer_size, // array_size is a smi.
+ array_size,
+ result,
+ elements_array_end,
+ scratch,
+ gc_required,
+ TAG_OBJECT);
+
+ // Allocated the JSArray. Now initialize the fields except for the elements
+ // array.
+ // result: JSObject
+ // elements_array: initial map
+ // elements_array_end: start of next object
+ // array_size: size of array (smi)
+ __ bind(&allocated);
+ __ mov(FieldOperand(result, JSObject::kMapOffset), elements_array);
+ __ mov(elements_array, Factory::empty_fixed_array());
+ __ mov(FieldOperand(result, JSArray::kPropertiesOffset), elements_array);
+ // Field JSArray::kElementsOffset is initialized later.
+ __ mov(FieldOperand(result, JSArray::kLengthOffset), array_size);
+
+ // Calculate the location of the elements array and set elements array member
+ // of the JSArray.
+ // result: JSObject
+ // elements_array_end: start of next object
+ // array_size: size of array (smi)
+ __ lea(elements_array, Operand(result, JSArray::kSize));
+ __ mov(FieldOperand(result, JSArray::kElementsOffset), elements_array);
+
+ // Initialize the fixed array. FixedArray length is not stored as a smi.
+ // result: JSObject
+ // elements_array: elements array
+ // elements_array_end: start of next object
+ // array_size: size of array (smi)
+ ASSERT(kSmiTag == 0);
+ __ shr(array_size, kSmiTagSize); // Convert from smi to value.
+ __ mov(FieldOperand(elements_array, JSObject::kMapOffset),
+ Factory::fixed_array_map());
+ Label not_empty_2, fill_array;
+ __ test(array_size, Operand(array_size));
+ __ j(not_zero, &not_empty_2);
+ // Length of the FixedArray is the number of pre-allocated elements even
+ // though the actual JSArray has length 0.
+ __ mov(FieldOperand(elements_array, Array::kLengthOffset),
+ Immediate(kPreallocatedArrayElements));
+ __ jmp(&fill_array);
+ __ bind(&not_empty_2);
+ // For non-empty JSArrays the length of the FixedArray and the JSArray is the
+ // same.
+ __ mov(FieldOperand(elements_array, Array::kLengthOffset), array_size);
+
+ // Fill the allocated FixedArray with the hole value if requested.
+ // result: JSObject
+ // elements_array: elements array
+ // elements_array_end: start of next object
+ __ bind(&fill_array);
+ if (fill_with_hole) {
+ Label loop, entry;
+ __ mov(scratch, Factory::the_hole_value());
+ __ lea(elements_array, Operand(elements_array,
+ FixedArray::kHeaderSize - kHeapObjectTag));
+ __ jmp(&entry);
+ __ bind(&loop);
+ __ mov(Operand(elements_array, 0), scratch);
+ __ add(Operand(elements_array), Immediate(kPointerSize));
+ __ bind(&entry);
+ __ cmp(elements_array, Operand(elements_array_end));
+ __ j(below, &loop);
+ }
+}
+
+
+// Create a new array for the built-in Array function. This function allocates
+// the JSArray object and the FixedArray elements array and initializes these.
+// If the Array cannot be constructed in native code the runtime is called. This
+// function assumes the following state:
+// edi: constructor (built-in Array function)
+// eax: argc
+// esp[0]: return address
+// esp[4]: last argument
+// This function is used for both construct and normal calls of Array. Whether
+// it is a construct call or not is indicated by the construct_call parameter.
+// The only difference between handling a construct call and a normal call is
+// that for a construct call the constructor function in edi needs to be
+// preserved for entering the generic code. In both cases argc in eax needs to
+// be preserved.
+static void ArrayNativeCode(MacroAssembler* masm,
+ bool construct_call,
+ Label *call_generic_code) {
+ Label argc_one_or_more, argc_two_or_more, prepare_generic_code_call;
+
+ // Push the constructor and argc. No need to tag argc as a smi, as there will
+ // be no garbage collection with this on the stack.
+ int push_count = 0;
+ if (construct_call) {
+ push_count++;
+ __ push(edi);
+ }
+ push_count++;
+ __ push(eax);
+
+ // Check for array construction with zero arguments.
+ __ test(eax, Operand(eax));
+ __ j(not_zero, &argc_one_or_more);
+
+ // Handle construction of an empty array.
+ AllocateEmptyJSArray(masm,
+ edi,
+ eax,
+ ebx,
+ ecx,
+ edi,
+ kPreallocatedArrayElements,
+ &prepare_generic_code_call);
+ __ IncrementCounter(&Counters::array_function_native, 1);
+ __ pop(ebx);
+ if (construct_call) {
+ __ pop(edi);
+ }
+ __ ret(kPointerSize);
+
+ // Check for one argument. Bail out if argument is not smi or if it is
+ // negative.
+ __ bind(&argc_one_or_more);
+ __ cmp(eax, 1);
+ __ j(not_equal, &argc_two_or_more);
+ ASSERT(kSmiTag == 0);
+ __ test(Operand(esp, (push_count + 1) * kPointerSize),
+ Immediate(kIntptrSignBit | kSmiTagMask));
+ __ j(not_zero, &prepare_generic_code_call);
+
+ // Handle construction of an empty array of a certain size. Get the size from
+ // the stack and bail out if size is to large to actually allocate an elements
+ // array.
+ __ mov(edx, Operand(esp, (push_count + 1) * kPointerSize));
+ ASSERT(kSmiTag == 0);
+ __ cmp(edx, JSObject::kInitialMaxFastElementArray << kSmiTagSize);
+ __ j(greater_equal, &prepare_generic_code_call);
+
+ // edx: array_size (smi)
+ // edi: constructor
+ // esp[0]: argc
+ // esp[4]: constructor (only if construct_call)
+ // esp[8]: return address
+ // esp[C]: argument
+ AllocateJSArray(masm,
+ edi,
+ edx,
+ eax,
+ ebx,
+ ecx,
+ edi,
+ true,
+ &prepare_generic_code_call);
+ __ IncrementCounter(&Counters::array_function_native, 1);
+ __ pop(ebx);
+ if (construct_call) {
+ __ pop(edi);
+ }
+ __ ret(2 * kPointerSize);
+
+ // Handle construction of an array from a list of arguments.
+ __ bind(&argc_two_or_more);
+ ASSERT(kSmiTag == 0);
+ __ shl(eax, kSmiTagSize); // Convet argc to a smi.
+ // eax: array_size (smi)
+ // edi: constructor
+ // esp[0] : argc
+ // esp[4]: constructor (only if construct_call)
+ // esp[8] : return address
+ // esp[C] : last argument
+ AllocateJSArray(masm,
+ edi,
+ eax,
+ ebx,
+ ecx,
+ edx,
+ edi,
+ false,
+ &prepare_generic_code_call);
+ __ IncrementCounter(&Counters::array_function_native, 1);
+ __ mov(eax, ebx);
+ __ pop(ebx);
+ if (construct_call) {
+ __ pop(edi);
+ }
+ __ push(eax);
+ // eax: JSArray
+ // ebx: argc
+ // edx: elements_array_end (untagged)
+ // esp[0]: JSArray
+ // esp[4]: return address
+ // esp[8]: last argument
+
+ // Location of the last argument
+ __ lea(edi, Operand(esp, 2 * kPointerSize));
+
+ // Location of the first array element (Parameter fill_with_holes to
+ // AllocateJSArrayis false, so the FixedArray is returned in ecx).
+ __ lea(edx, Operand(ecx, FixedArray::kHeaderSize - kHeapObjectTag));
+
+ // ebx: argc
+ // edx: location of the first array element
+ // edi: location of the last argument
+ // esp[0]: JSArray
+ // esp[4]: return address
+ // esp[8]: last argument
+ Label loop, entry;
+ __ mov(ecx, ebx);
+ __ jmp(&entry);
+ __ bind(&loop);
+ __ mov(eax, Operand(edi, ecx, times_pointer_size, 0));
+ __ mov(Operand(edx, 0), eax);
+ __ add(Operand(edx), Immediate(kPointerSize));
+ __ bind(&entry);
+ __ dec(ecx);
+ __ j(greater_equal, &loop);
+
+ // Remove caller arguments from the stack and return.
+ // ebx: argc
+ // esp[0]: JSArray
+ // esp[4]: return address
+ // esp[8]: last argument
+ __ pop(eax);
+ __ pop(ecx);
+ __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize));
+ __ push(ecx);
+ __ ret(0);
+
+ // Restore argc and constructor before running the generic code.
+ __ bind(&prepare_generic_code_call);
+ __ pop(eax);
+ if (construct_call) {
+ __ pop(edi);
+ }
+ __ jmp(call_generic_code);
+}
+
+
+void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- eax : argc
+ // -- esp[0] : return address
+ // -- esp[4] : last argument
+ // -----------------------------------
+ Label generic_array_code, one_or_more_arguments, two_or_more_arguments;
+
+ // Get the Array function.
+ GenerateLoadArrayFunction(masm, edi);
+
+ if (FLAG_debug_code) {
+ // Initial map for the builtin Array function shoud be a map.
+ __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
+ // Will both indicate a NULL and a Smi.
+ __ test(ebx, Immediate(kSmiTagMask));
+ __ Assert(not_zero, "Unexpected initial map for Array function");
+ __ CmpObjectType(ebx, MAP_TYPE, ecx);
+ __ Assert(equal, "Unexpected initial map for Array function");
+ }
+
+ // Run the native code for the Array function called as a normal function.
+ ArrayNativeCode(masm, false, &generic_array_code);
+
+ // Jump to the generic array code in case the specialized code cannot handle
+ // the construction.
+ __ bind(&generic_array_code);
+ Code* code = Builtins::builtin(Builtins::ArrayCodeGeneric);
+ Handle<Code> array_code(code);
+ __ jmp(array_code, RelocInfo::CODE_TARGET);
+}
+
+
+void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
+ // ----------- S t a t e -------------
+ // -- eax : argc
+ // -- edi : constructor
+ // -- esp[0] : return address
+ // -- esp[4] : last argument
+ // -----------------------------------
+ Label generic_constructor;
+
+ if (FLAG_debug_code) {
+ // The array construct code is only set for the builtin Array function which
+ // does always have a map.
+ GenerateLoadArrayFunction(masm, ebx);
+ __ cmp(edi, Operand(ebx));
+ __ Assert(equal, "Unexpected Array function");
+ // Initial map for the builtin Array function should be a map.
+ __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
+ // Will both indicate a NULL and a Smi.
+ __ test(ebx, Immediate(kSmiTagMask));
+ __ Assert(not_zero, "Unexpected initial map for Array function");
+ __ CmpObjectType(ebx, MAP_TYPE, ecx);
+ __ Assert(equal, "Unexpected initial map for Array function");
+ }
+
+ // Run the native code for the Array function called as constructor.
+ ArrayNativeCode(masm, true, &generic_constructor);
+
+ // Jump to the generic construct code in case the specialized code cannot
+ // handle the construction.
+ __ bind(&generic_constructor);
+ Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
+ Handle<Code> generic_construct_stub(code);
+ __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET);
+}
+
+
static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
__ push(ebp);
__ mov(ebp, Operand(esp));
diff --git a/deps/v8/src/log-utils.cc b/deps/v8/src/log-utils.cc
index b31864be46..dcb4b499e6 100644
--- a/deps/v8/src/log-utils.cc
+++ b/deps/v8/src/log-utils.cc
@@ -310,6 +310,20 @@ void LogMessageBuilder::AppendDetailed(String* str, bool show_impl_info) {
}
+void LogMessageBuilder::AppendStringPart(const char* str, int len) {
+ if (pos_ + len > Log::kMessageBufferSize) {
+ len = Log::kMessageBufferSize - pos_;
+ ASSERT(len >= 0);
+ if (len == 0) return;
+ }
+ Vector<char> buf(Log::message_buffer_ + pos_,
+ Log::kMessageBufferSize - pos_);
+ OS::StrNCpy(buf, str, len);
+ pos_ += len;
+ ASSERT(pos_ <= Log::kMessageBufferSize);
+}
+
+
bool LogMessageBuilder::StoreInCompressor(LogRecordCompressor* compressor) {
return compressor->Store(Vector<const char>(Log::message_buffer_, pos_));
}
diff --git a/deps/v8/src/log-utils.h b/deps/v8/src/log-utils.h
index ad669d53d7..117f098cc8 100644
--- a/deps/v8/src/log-utils.h
+++ b/deps/v8/src/log-utils.h
@@ -114,6 +114,9 @@ class Log : public AllStatic {
return !is_stopped_ && (output_handle_ != NULL || output_buffer_ != NULL);
}
+ // Size of buffer used for formatting log messages.
+ static const int kMessageBufferSize = 2048;
+
private:
typedef int (*WritePtr)(const char* msg, int length);
@@ -162,9 +165,6 @@ class Log : public AllStatic {
// access to the formatting buffer and the log file or log memory buffer.
static Mutex* mutex_;
- // Size of buffer used for formatting log messages.
- static const int kMessageBufferSize = 2048;
-
// Buffer used for formatting log messages. This is a singleton buffer and
// mutex_ should be acquired before using it.
static char* message_buffer_;
@@ -247,6 +247,9 @@ class LogMessageBuilder BASE_EMBEDDED {
void AppendDetailed(String* str, bool show_impl_info);
+ // Append a portion of a string.
+ void AppendStringPart(const char* str, int len);
+
// Stores log message into compressor, returns true if the message
// was stored (i.e. doesn't repeat the previous one).
bool StoreInCompressor(LogRecordCompressor* compressor);
diff --git a/deps/v8/src/log.cc b/deps/v8/src/log.cc
index 6bbefbceb1..d225c3b495 100644
--- a/deps/v8/src/log.cc
+++ b/deps/v8/src/log.cc
@@ -889,14 +889,51 @@ void Logger::HeapSampleJSConstructorEvent(const char* constructor,
#ifdef ENABLE_LOGGING_AND_PROFILING
if (!Log::IsEnabled() || !FLAG_log_gc) return;
LogMessageBuilder msg;
- msg.Append("heap-js-cons-item,%s,%d,%d\n",
- constructor[0] != '\0' ? constructor : "(anonymous)",
- number, bytes);
+ msg.Append("heap-js-cons-item,%s,%d,%d\n", constructor, number, bytes);
msg.WriteToLogFile();
#endif
}
+void Logger::HeapSampleJSRetainersEvent(
+ const char* constructor, const char* event) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ if (!Log::IsEnabled() || !FLAG_log_gc) return;
+ // Event starts with comma, so we don't have it in the format string.
+ static const char* event_text = "heap-js-ret-item,%s";
+ // We take placeholder strings into account, but it's OK to be conservative.
+ static const int event_text_len = strlen(event_text);
+ const int cons_len = strlen(constructor), event_len = strlen(event);
+ int pos = 0;
+ // Retainer lists can be long. We may need to split them into multiple events.
+ do {
+ LogMessageBuilder msg;
+ msg.Append(event_text, constructor);
+ int to_write = event_len - pos;
+ if (to_write > Log::kMessageBufferSize - (cons_len + event_text_len)) {
+ int cut_pos = pos + Log::kMessageBufferSize - (cons_len + event_text_len);
+ ASSERT(cut_pos < event_len);
+ while (cut_pos > pos && event[cut_pos] != ',') --cut_pos;
+ if (event[cut_pos] != ',') {
+ // Crash in debug mode, skip in release mode.
+ ASSERT(false);
+ return;
+ }
+ // Append a piece of event that fits, without trailing comma.
+ msg.AppendStringPart(event + pos, cut_pos - pos);
+ // Start next piece with comma.
+ pos = cut_pos;
+ } else {
+ msg.Append("%s", event + pos);
+ pos += event_len;
+ }
+ msg.Append('\n');
+ msg.WriteToLogFile();
+ } while (pos < event_len);
+#endif
+}
+
+
void Logger::DebugTag(const char* call_site_tag) {
#ifdef ENABLE_LOGGING_AND_PROFILING
if (!Log::IsEnabled() || !FLAG_log) return;
diff --git a/deps/v8/src/log.h b/deps/v8/src/log.h
index 89f6cdb391..07a0429ace 100644
--- a/deps/v8/src/log.h
+++ b/deps/v8/src/log.h
@@ -221,6 +221,8 @@ class Logger {
static void HeapSampleItemEvent(const char* type, int number, int bytes);
static void HeapSampleJSConstructorEvent(const char* constructor,
int number, int bytes);
+ static void HeapSampleJSRetainersEvent(const char* constructor,
+ const char* event);
static void HeapSampleStats(const char* space, const char* kind,
int capacity, int used);
diff --git a/deps/v8/src/mark-compact.cc b/deps/v8/src/mark-compact.cc
index 8a51541752..cbd47a8763 100644
--- a/deps/v8/src/mark-compact.cc
+++ b/deps/v8/src/mark-compact.cc
@@ -265,18 +265,6 @@ class MarkingVisitor : public ObjectVisitor {
for (Object** p = start; p < end; p++) MarkObjectByPointer(p);
}
- void BeginCodeIteration(Code* code) {
- // When iterating over a code object during marking
- // ic targets are derived pointers.
- ASSERT(code->ic_flag() == Code::IC_TARGET_IS_ADDRESS);
- }
-
- void EndCodeIteration(Code* code) {
- // If this is a compacting collection, set ic targets
- // are pointing to object headers.
- if (IsCompacting()) code->set_ic_flag(Code::IC_TARGET_IS_OBJECT);
- }
-
void VisitCodeTarget(RelocInfo* rinfo) {
ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
Code* code = Code::GetCodeFromTargetAddress(rinfo->target_address());
@@ -287,11 +275,6 @@ class MarkingVisitor : public ObjectVisitor {
} else {
MarkCompactCollector::MarkObject(code);
}
- if (IsCompacting()) {
- // When compacting we convert the target to a real object pointer.
- code = Code::GetCodeFromTargetAddress(rinfo->target_address());
- rinfo->set_target_object(code);
- }
}
void VisitDebugTarget(RelocInfo* rinfo) {
@@ -1187,12 +1170,6 @@ static void SweepSpace(PagedSpace* space, DeallocateFunction dealloc) {
if (object->IsMarked()) {
object->ClearMark();
MarkCompactCollector::tracer()->decrement_marked_count();
- if (MarkCompactCollector::IsCompacting() && object->IsCode()) {
- // If this is compacting collection marked code objects have had
- // their IC targets converted to objects.
- // They need to be converted back to addresses.
- Code::cast(object)->ConvertICTargetsFromObjectToAddress();
- }
if (!is_previous_alive) { // Transition from free to live.
dealloc(free_start, current - free_start);
is_previous_alive = true;
@@ -1398,6 +1375,14 @@ class UpdatingVisitor: public ObjectVisitor {
for (Object** p = start; p < end; p++) UpdatePointer(p);
}
+ void VisitCodeTarget(RelocInfo* rinfo) {
+ ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
+ Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
+ VisitPointer(&target);
+ rinfo->set_target_address(
+ reinterpret_cast<Code*>(target)->instruction_start());
+ }
+
private:
void UpdatePointer(Object** p) {
if (!(*p)->IsHeapObject()) return;
@@ -1631,11 +1616,6 @@ void MarkCompactCollector::RelocateObjects() {
ASSERT(live_cells == live_cell_objects_);
ASSERT(live_news == live_young_objects_);
- // Notify code object in LO to convert IC target to address
- // This must happen after lo_space_->Compact
- LargeObjectIterator it(Heap::lo_space());
- while (it.has_next()) { ConvertCodeICTargetToAddress(it.next()); }
-
// Flip from and to spaces
Heap::new_space()->Flip();
@@ -1654,14 +1634,6 @@ void MarkCompactCollector::RelocateObjects() {
}
-int MarkCompactCollector::ConvertCodeICTargetToAddress(HeapObject* obj) {
- if (obj->IsCode()) {
- Code::cast(obj)->ConvertICTargetsFromObjectToAddress();
- }
- return obj->Size();
-}
-
-
int MarkCompactCollector::RelocateMapObject(HeapObject* obj) {
// Recover map pointer.
MapWord encoding = obj->map_word();
@@ -1770,11 +1742,6 @@ int MarkCompactCollector::RelocateCodeObject(HeapObject* obj) {
// Reset the map pointer.
int obj_size = RestoreMap(obj, Heap::code_space(), new_addr, map_addr);
- // Convert inline cache target to address using old address.
- if (obj->IsCode()) {
- Code::cast(obj)->ConvertICTargetsFromObjectToAddress();
- }
-
Address old_addr = obj->address();
if (new_addr != old_addr) {
diff --git a/deps/v8/src/messages.js b/deps/v8/src/messages.js
index 255e544099..6513067135 100644
--- a/deps/v8/src/messages.js
+++ b/deps/v8/src/messages.js
@@ -167,7 +167,8 @@ function FormatMessage(message) {
no_input_to_regexp: "No input to %0",
result_not_primitive: "Result of %0 must be a primitive, was %1",
invalid_json: "String '%0' is not valid JSON",
- circular_structure: "Converting circular structure to JSON"
+ circular_structure: "Converting circular structure to JSON",
+ object_keys_non_object: "Object.keys called on non-object"
};
}
var format = kMessages[message.type];
diff --git a/deps/v8/src/objects-debug.cc b/deps/v8/src/objects-debug.cc
index 9fc9b1d4ef..288cc21ecb 100644
--- a/deps/v8/src/objects-debug.cc
+++ b/deps/v8/src/objects-debug.cc
@@ -733,7 +733,6 @@ void Code::CodePrint() {
void Code::CodeVerify() {
- CHECK(ic_flag() == IC_TARGET_IS_ADDRESS);
CHECK(IsAligned(reinterpret_cast<intptr_t>(instruction_start()),
static_cast<intptr_t>(kCodeAlignment)));
Address last_gc_pc = NULL;
diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h
index cabc8a2187..29b886d87b 100644
--- a/deps/v8/src/objects-inl.h
+++ b/deps/v8/src/objects-inl.h
@@ -2538,16 +2538,6 @@ INT_ACCESSORS(Code, relocation_size, kRelocationSizeOffset)
INT_ACCESSORS(Code, sinfo_size, kSInfoSizeOffset)
-Code::ICTargetState Code::ic_flag() {
- return static_cast<ICTargetState>(READ_BYTE_FIELD(this, kICFlagOffset));
-}
-
-
-void Code::set_ic_flag(ICTargetState value) {
- WRITE_BYTE_FIELD(this, kICFlagOffset, value);
-}
-
-
byte* Code::instruction_start() {
return FIELD_ADDR(this, kHeaderSize);
}
diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc
index 2b6f83fdac..ea2c202c9e 100644
--- a/deps/v8/src/objects.cc
+++ b/deps/v8/src/objects.cc
@@ -476,6 +476,21 @@ Object* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
}
+bool JSObject::IsDirty() {
+ Object* cons_obj = map()->constructor();
+ if (!cons_obj->IsJSFunction())
+ return true;
+ JSFunction* fun = JSFunction::cast(cons_obj);
+ if (!fun->shared()->function_data()->IsFunctionTemplateInfo())
+ return true;
+ // If the object is fully fast case and has the same map it was
+ // created with then no changes can have been made to it.
+ return map() != fun->initial_map()
+ || !HasFastElements()
+ || !HasFastProperties();
+}
+
+
Object* Object::GetProperty(Object* receiver,
LookupResult* result,
String* name,
@@ -4940,60 +4955,25 @@ void SharedFunctionInfo::SharedFunctionInfoIterateBody(ObjectVisitor* v) {
}
-void ObjectVisitor::BeginCodeIteration(Code* code) {
- ASSERT(code->ic_flag() == Code::IC_TARGET_IS_OBJECT);
-}
-
-
void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
- VisitPointer(rinfo->target_object_address());
+ Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
+ Object* old_target = target;
+ VisitPointer(&target);
+ CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
}
void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()) && rinfo->IsCallInstruction());
- VisitPointer(rinfo->call_object_address());
-}
-
-
-// Convert relocatable targets from address to code object address. This is
-// mainly IC call targets but for debugging straight-line code can be replaced
-// with a call instruction which also has to be relocated.
-void Code::ConvertICTargetsFromAddressToObject() {
- ASSERT(ic_flag() == IC_TARGET_IS_ADDRESS);
-
- for (RelocIterator it(this, RelocInfo::kCodeTargetMask);
- !it.done(); it.next()) {
- Address ic_addr = it.rinfo()->target_address();
- ASSERT(ic_addr != NULL);
- HeapObject* code = Code::GetCodeFromTargetAddress(ic_addr);
- ASSERT(code->IsHeapObject());
- it.rinfo()->set_target_object(code);
- }
-
-#ifdef ENABLE_DEBUGGER_SUPPORT
- if (Debug::has_break_points()) {
- for (RelocIterator it(this, RelocInfo::ModeMask(RelocInfo::JS_RETURN));
- !it.done();
- it.next()) {
- if (it.rinfo()->IsCallInstruction()) {
- Address addr = it.rinfo()->call_address();
- ASSERT(addr != NULL);
- HeapObject* code = Code::GetCodeFromTargetAddress(addr);
- ASSERT(code->IsHeapObject());
- it.rinfo()->set_call_object(code);
- }
- }
- }
-#endif
- set_ic_flag(IC_TARGET_IS_OBJECT);
+ Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
+ Object* old_target = target;
+ VisitPointer(&target);
+ CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
}
void Code::CodeIterateBody(ObjectVisitor* v) {
- v->BeginCodeIteration(this);
-
int mode_mask = RelocInfo::kCodeTargetMask |
RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
@@ -5020,38 +5000,6 @@ void Code::CodeIterateBody(ObjectVisitor* v) {
}
ScopeInfo<>::IterateScopeInfo(this, v);
-
- v->EndCodeIteration(this);
-}
-
-
-void Code::ConvertICTargetsFromObjectToAddress() {
- ASSERT(ic_flag() == IC_TARGET_IS_OBJECT);
-
- for (RelocIterator it(this, RelocInfo::kCodeTargetMask);
- !it.done(); it.next()) {
- // We cannot use the safe cast (Code::cast) here, because we may be in
- // the middle of relocating old objects during GC and the map pointer in
- // the code object may be mangled
- Code* code = reinterpret_cast<Code*>(it.rinfo()->target_object());
- ASSERT((code != NULL) && code->IsHeapObject());
- it.rinfo()->set_target_address(code->instruction_start());
- }
-
-#ifdef ENABLE_DEBUGGER_SUPPORT
- if (Debug::has_break_points()) {
- for (RelocIterator it(this, RelocInfo::ModeMask(RelocInfo::JS_RETURN));
- !it.done();
- it.next()) {
- if (it.rinfo()->IsCallInstruction()) {
- Code* code = reinterpret_cast<Code*>(it.rinfo()->call_object());
- ASSERT((code != NULL) && code->IsHeapObject());
- it.rinfo()->set_call_address(code->instruction_start());
- }
- }
- }
-#endif
- set_ic_flag(IC_TARGET_IS_ADDRESS);
}
diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h
index feeddcb675..5de9afabea 100644
--- a/deps/v8/src/objects.h
+++ b/deps/v8/src/objects.h
@@ -1428,6 +1428,10 @@ class JSObject: public HeapObject {
// Tells whether this object needs to be loaded.
inline bool IsLoaded();
+ // Returns true if this is an instance of an api function and has
+ // been modified since it was created. May give false positives.
+ bool IsDirty();
+
bool HasProperty(String* name) {
return GetPropertyAttribute(name) != ABSENT;
}
@@ -2516,13 +2520,6 @@ class Code: public HeapObject {
NUMBER_OF_KINDS = KEYED_STORE_IC + 1
};
- // A state indicates that inline cache in this Code object contains
- // objects or relative instruction addresses.
- enum ICTargetState {
- IC_TARGET_IS_ADDRESS,
- IC_TARGET_IS_OBJECT
- };
-
#ifdef ENABLE_DISASSEMBLER
// Printing
static const char* Kind2String(Kind kind);
@@ -2562,12 +2559,6 @@ class Code: public HeapObject {
inline bool is_keyed_store_stub() { return kind() == KEYED_STORE_IC; }
inline bool is_call_stub() { return kind() == CALL_IC; }
- // [ic_flag]: State of inline cache targets. The flag is set to the
- // object variant in ConvertICTargetsFromAddressToObject, and set to
- // the address variant in ConvertICTargetsFromObjectToAddress.
- inline ICTargetState ic_flag();
- inline void set_ic_flag(ICTargetState value);
-
// [major_key]: For kind STUB, the major key.
inline CodeStub::Major major_key();
inline void set_major_key(CodeStub::Major major);
@@ -2613,12 +2604,6 @@ class Code: public HeapObject {
// Returns the address of the scope information.
inline byte* sinfo_start();
- // Convert inline cache target from address to code object before GC.
- void ConvertICTargetsFromAddressToObject();
-
- // Convert inline cache target from code object to address after GC
- void ConvertICTargetsFromObjectToAddress();
-
// Relocate the code by delta bytes. Called to signal that this code
// object has been moved by delta bytes.
void Relocate(int delta);
@@ -2674,7 +2659,6 @@ class Code: public HeapObject {
~kCodeAlignmentMask;
// Byte offsets within kKindSpecificFlagsOffset.
- static const int kICFlagOffset = kKindSpecificFlagsOffset + 0;
static const int kStubMajorKeyOffset = kKindSpecificFlagsOffset + 1;
// Flags layout.
@@ -4806,9 +4790,6 @@ class ObjectVisitor BASE_EMBEDDED {
// To allow lazy clearing of inline caches the visitor has
// a rich interface for iterating over Code objects..
- // Called prior to visiting the body of a Code object.
- virtual void BeginCodeIteration(Code* code);
-
// Visits a code target in the instruction stream.
virtual void VisitCodeTarget(RelocInfo* rinfo);
@@ -4818,9 +4799,6 @@ class ObjectVisitor BASE_EMBEDDED {
// Visits a debug call target in the instruction stream.
virtual void VisitDebugTarget(RelocInfo* rinfo);
- // Called after completing visiting the body of a Code object.
- virtual void EndCodeIteration(Code* code) {}
-
// Handy shorthand for visiting a single pointer.
virtual void VisitPointer(Object** p) { VisitPointers(p, p + 1); }
diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc
index 6272827b45..06b61e7bcb 100644
--- a/deps/v8/src/runtime.cc
+++ b/deps/v8/src/runtime.cc
@@ -1208,6 +1208,14 @@ static Object* Runtime_FunctionIsAPIFunction(Arguments args) {
: Heap::false_value();
}
+static Object* Runtime_FunctionIsBuiltin(Arguments args) {
+ NoHandleAllocation ha;
+ ASSERT(args.length() == 1);
+
+ CONVERT_CHECKED(JSFunction, f, args[0]);
+ return f->IsBuiltin() ? Heap::true_value() : Heap::false_value();
+}
+
static Object* Runtime_SetCode(Arguments args) {
HandleScope scope;
@@ -2992,7 +3000,8 @@ static Object* Runtime_GetPropertyNamesFast(Arguments args) {
HandleScope scope;
Handle<JSObject> object(raw_object);
- Handle<FixedArray> content = GetKeysInFixedArrayFor(object);
+ Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
+ INCLUDE_PROTOS);
// Test again, since cache may have been built by preceding call.
if (object->IsSimpleEnum()) return object->map();
@@ -3001,6 +3010,22 @@ static Object* Runtime_GetPropertyNamesFast(Arguments args) {
}
+static Object* Runtime_LocalKeys(Arguments args) {
+ ASSERT_EQ(args.length(), 1);
+ CONVERT_CHECKED(JSObject, raw_object, args[0]);
+ HandleScope scope;
+ Handle<JSObject> object(raw_object);
+ Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
+ LOCAL_ONLY);
+ // Some fast paths through GetKeysInFixedArrayFor reuse a cached
+ // property array and since the result is mutable we have to create
+ // a fresh clone on each invocation.
+ Handle<FixedArray> copy = Factory::NewFixedArray(contents->length());
+ contents->CopyTo(0, *copy, 0, contents->length());
+ return *Factory::NewJSArrayWithElements(copy);
+}
+
+
static Object* Runtime_GetArgumentsProperty(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);
@@ -5516,7 +5541,7 @@ static Object* Runtime_GetArrayKeys(Arguments args) {
if (array->elements()->IsDictionary()) {
// Create an array and get all the keys into it, then remove all the
// keys that are not integers in the range 0 to length-1.
- Handle<FixedArray> keys = GetKeysInFixedArrayFor(array);
+ Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
int keys_length = keys->length();
for (int i = 0; i < keys_length; i++) {
Object* key = keys->get(i);
@@ -5738,55 +5763,51 @@ static Object* Runtime_DebugGetPropertyDetails(Arguments args) {
int length = LocalPrototypeChainLength(*obj);
// Try local lookup on each of the objects.
- LookupResult result;
Handle<JSObject> jsproto = obj;
for (int i = 0; i < length; i++) {
+ LookupResult result;
jsproto->LocalLookup(*name, &result);
if (result.IsProperty()) {
- break;
+ // LookupResult is not GC safe as it holds raw object pointers.
+ // GC can happen later in this code so put the required fields into
+ // local variables using handles when required for later use.
+ PropertyType result_type = result.type();
+ Handle<Object> result_callback_obj;
+ if (result_type == CALLBACKS) {
+ result_callback_obj = Handle<Object>(result.GetCallbackObject());
+ }
+ Smi* property_details = result.GetPropertyDetails().AsSmi();
+ // DebugLookupResultValue can cause GC so details from LookupResult needs
+ // to be copied to handles before this.
+ bool caught_exception = false;
+ Object* raw_value = DebugLookupResultValue(*obj, *name, &result,
+ &caught_exception);
+ if (raw_value->IsFailure()) return raw_value;
+ Handle<Object> value(raw_value);
+
+ // If the callback object is a fixed array then it contains JavaScript
+ // getter and/or setter.
+ bool hasJavaScriptAccessors = result_type == CALLBACKS &&
+ result_callback_obj->IsFixedArray();
+ Handle<FixedArray> details =
+ Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
+ details->set(0, *value);
+ details->set(1, property_details);
+ if (hasJavaScriptAccessors) {
+ details->set(2,
+ caught_exception ? Heap::true_value()
+ : Heap::false_value());
+ details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
+ details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
+ }
+
+ return *Factory::NewJSArrayWithElements(details);
}
if (i < length - 1) {
jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
}
}
- if (result.IsProperty()) {
- // LookupResult is not GC safe as all its members are raw object pointers.
- // When calling DebugLookupResultValue GC can happen as this might invoke
- // callbacks. After the call to DebugLookupResultValue the callback object
- // in the LookupResult might still be needed. Put it into a handle for later
- // use.
- PropertyType result_type = result.type();
- Handle<Object> result_callback_obj;
- if (result_type == CALLBACKS) {
- result_callback_obj = Handle<Object>(result.GetCallbackObject());
- }
-
- // Find the actual value. Don't use result after this call as it's content
- // can be invalid.
- bool caught_exception = false;
- Object* value = DebugLookupResultValue(*obj, *name, &result,
- &caught_exception);
- if (value->IsFailure()) return value;
- Handle<Object> value_handle(value);
-
- // If the callback object is a fixed array then it contains JavaScript
- // getter and/or setter.
- bool hasJavaScriptAccessors = result_type == CALLBACKS &&
- result_callback_obj->IsFixedArray();
- Handle<FixedArray> details =
- Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
- details->set(0, *value_handle);
- details->set(1, result.GetPropertyDetails().AsSmi());
- if (hasJavaScriptAccessors) {
- details->set(2,
- caught_exception ? Heap::true_value() : Heap::false_value());
- details->set(3, FixedArray::cast(result.GetCallbackObject())->get(0));
- details->set(4, FixedArray::cast(result.GetCallbackObject())->get(1));
- }
-
- return *Factory::NewJSArrayWithElements(details);
- }
return Heap::undefined_value();
}
@@ -6271,7 +6292,7 @@ static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
if (function_context->has_extension() &&
!function_context->IsGlobalContext()) {
Handle<JSObject> ext(JSObject::cast(function_context->extension()));
- Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext);
+ Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
for (int i = 0; i < keys->length(); i++) {
// Names of variables introduced by eval are strings.
ASSERT(keys->get(i)->IsString());
@@ -6320,7 +6341,7 @@ static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
// be variables introduced by eval.
if (context->has_extension()) {
Handle<JSObject> ext(JSObject::cast(context->extension()));
- Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext);
+ Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
for (int i = 0; i < keys->length(); i++) {
// Names of variables introduced by eval are strings.
ASSERT(keys->get(i)->IsString());
diff --git a/deps/v8/src/runtime.h b/deps/v8/src/runtime.h
index ca38baf8ee..afa278b135 100644
--- a/deps/v8/src/runtime.h
+++ b/deps/v8/src/runtime.h
@@ -171,6 +171,7 @@ namespace internal {
F(FunctionGetScriptSourcePosition, 1, 1) \
F(FunctionGetPositionForOffset, 2, 1) \
F(FunctionIsAPIFunction, 1, 1) \
+ F(FunctionIsBuiltin, 1, 1) \
F(GetScript, 1, 1) \
F(CollectStackTrace, 2, 1) \
\
@@ -258,6 +259,8 @@ namespace internal {
F(Abort, 2, 1) \
/* Logging */ \
F(Log, 2, 1) \
+ /* ES5 */ \
+ F(LocalKeys, 1, 1) \
\
/* Pseudo functions - handled as macros by parser */ \
F(IS_VAR, 1, 1)
diff --git a/deps/v8/src/serialize.cc b/deps/v8/src/serialize.cc
index c89476241a..b6a9d9434a 100644
--- a/deps/v8/src/serialize.cc
+++ b/deps/v8/src/serialize.cc
@@ -935,6 +935,15 @@ class ReferenceUpdater: public ObjectVisitor {
}
}
+ virtual void VisitCodeTarget(RelocInfo* rinfo) {
+ ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
+ Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
+ Address encoded_target = serializer_->GetSavedAddress(target);
+ offsets_.Add(rinfo->target_address_address() - obj_address_);
+ addresses_.Add(encoded_target);
+ }
+
+
virtual void VisitExternalReferences(Address* start, Address* end) {
for (Address* p = start; p < end; ++p) {
uint32_t code = reference_encoder_->Encode(*p);
@@ -1093,6 +1102,14 @@ void Serializer::VisitPointers(Object** start, Object** end) {
}
+void Serializer::VisitCodeTarget(RelocInfo* rinfo) {
+ ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
+ Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
+ bool serialized;
+ Encode(target, &serialized);
+}
+
+
class GlobalHandlesRetriever: public ObjectVisitor {
public:
explicit GlobalHandlesRetriever(List<Object**>* handles)
@@ -1255,10 +1272,7 @@ Address Serializer::PutObject(HeapObject* obj) {
SaveAddress(obj, addr);
if (type == CODE_TYPE) {
- Code* code = Code::cast(obj);
- // Ensure Code objects contain Object pointers, not Addresses.
- code->ConvertICTargetsFromAddressToObject();
- LOG(CodeMoveEvent(code->address(), addr));
+ LOG(CodeMoveEvent(obj->address(), addr));
}
// Write out the object prologue: type, size, and simulated address of obj.
@@ -1290,12 +1304,6 @@ Address Serializer::PutObject(HeapObject* obj) {
}
#endif
- if (type == CODE_TYPE) {
- Code* code = Code::cast(obj);
- // Convert relocations from Object* to Address in Code objects
- code->ConvertICTargetsFromObjectToAddress();
- }
-
objects_++;
return addr;
}
@@ -1422,6 +1430,14 @@ void Deserializer::VisitPointers(Object** start, Object** end) {
}
+void Deserializer::VisitCodeTarget(RelocInfo* rinfo) {
+ ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
+ Address encoded_address = reinterpret_cast<Address>(rinfo->target_object());
+ Code* target_object = reinterpret_cast<Code*>(Resolve(encoded_address));
+ rinfo->set_target_address(target_object->instruction_start());
+}
+
+
void Deserializer::VisitExternalReferences(Address* start, Address* end) {
for (Address* p = start; p < end; ++p) {
uint32_t code = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(*p));
@@ -1617,8 +1633,6 @@ Object* Deserializer::GetObject() {
if (type == CODE_TYPE) {
Code* code = Code::cast(obj);
- // Convert relocations from Object* to Address in Code objects
- code->ConvertICTargetsFromObjectToAddress();
LOG(CodeMoveEvent(a, code->address()));
}
objects_++;
diff --git a/deps/v8/src/serialize.h b/deps/v8/src/serialize.h
index f5780ae35b..c901480fe5 100644
--- a/deps/v8/src/serialize.h
+++ b/deps/v8/src/serialize.h
@@ -155,7 +155,7 @@ class Serializer: public ObjectVisitor {
friend class ReferenceUpdater;
virtual void VisitPointers(Object** start, Object** end);
-
+ virtual void VisitCodeTarget(RelocInfo* rinfo);
bool IsVisited(HeapObject* obj);
Address GetSavedAddress(HeapObject* obj);
@@ -289,6 +289,7 @@ class Deserializer: public ObjectVisitor {
private:
virtual void VisitPointers(Object** start, Object** end);
+ virtual void VisitCodeTarget(RelocInfo* rinfo);
virtual void VisitExternalReferences(Address* start, Address* end);
virtual void VisitRuntimeEntry(RelocInfo* rinfo);
diff --git a/deps/v8/src/spaces.cc b/deps/v8/src/spaces.cc
index de9b233637..998debb30b 100644
--- a/deps/v8/src/spaces.cc
+++ b/deps/v8/src/spaces.cc
@@ -827,13 +827,7 @@ void PagedSpace::Verify(ObjectVisitor* visitor) {
// have their remembered set bits set if required as determined
// by the visitor.
int size = object->Size();
- if (object->IsCode()) {
- Code::cast(object)->ConvertICTargetsFromAddressToObject();
- object->IterateBody(map->instance_type(), size, visitor);
- Code::cast(object)->ConvertICTargetsFromObjectToAddress();
- } else {
- object->IterateBody(map->instance_type(), size, visitor);
- }
+ object->IterateBody(map->instance_type(), size, visitor);
current += size;
}
@@ -1906,7 +1900,7 @@ void OldSpace::ReportStatistics() {
int rset = Memory::int_at(rset_addr);
if (rset != 0) {
// Bits were set
- int intoff = rset_addr - p->address();
+ int intoff = rset_addr - p->address() - Page::kRSetOffset;
int bitoff = 0;
for (; bitoff < kBitsPerInt; ++bitoff) {
if ((rset & (1 << bitoff)) != 0) {
@@ -2171,7 +2165,7 @@ void FixedSpace::ReportStatistics() {
int rset = Memory::int_at(rset_addr);
if (rset != 0) {
// Bits were set
- int intoff = rset_addr - p->address();
+ int intoff = rset_addr - p->address() - Page::kRSetOffset;
int bitoff = 0;
for (; bitoff < kBitsPerInt; ++bitoff) {
if ((rset & (1 << bitoff)) != 0) {
@@ -2574,11 +2568,9 @@ void LargeObjectSpace::Verify() {
// Byte arrays and strings don't have interior pointers.
if (object->IsCode()) {
VerifyPointersVisitor code_visitor;
- Code::cast(object)->ConvertICTargetsFromAddressToObject();
object->IterateBody(map->instance_type(),
object->Size(),
&code_visitor);
- Code::cast(object)->ConvertICTargetsFromObjectToAddress();
} else if (object->IsFixedArray()) {
// We loop over fixed arrays ourselves, rather then using the visitor,
// because the visitor doesn't support the start/offset iteration
diff --git a/deps/v8/src/string-stream.cc b/deps/v8/src/string-stream.cc
index cec4167a98..8c62a45f92 100644
--- a/deps/v8/src/string-stream.cc
+++ b/deps/v8/src/string-stream.cc
@@ -251,7 +251,7 @@ void StringStream::Add(const char* format, FmtElm arg0, FmtElm arg1,
}
-SmartPointer<const char> StringStream::ToCString() {
+SmartPointer<const char> StringStream::ToCString() const {
char* str = NewArray<char>(length_ + 1);
memcpy(str, buffer_, length_);
str[length_] = '\0';
diff --git a/deps/v8/src/string-stream.h b/deps/v8/src/string-stream.h
index 6649f18313..323a6d6633 100644
--- a/deps/v8/src/string-stream.h
+++ b/deps/v8/src/string-stream.h
@@ -141,7 +141,7 @@ class StringStream {
void OutputToStdOut();
void Log();
Handle<String> ToString();
- SmartPointer<const char> ToCString();
+ SmartPointer<const char> ToCString() const;
// Object printing support.
void PrintName(Object* o);
diff --git a/deps/v8/src/v8-counters.h b/deps/v8/src/v8-counters.h
index 0b941f672b..e360b55768 100644
--- a/deps/v8/src/v8-counters.h
+++ b/deps/v8/src/v8-counters.h
@@ -142,6 +142,8 @@ namespace internal {
SC(constructed_objects, V8.ConstructedObjects) \
SC(constructed_objects_runtime, V8.ConstructedObjectsRuntime) \
SC(constructed_objects_stub, V8.ConstructedObjectsStub) \
+ SC(array_function_runtime, V8.ArrayFunctionRuntime) \
+ SC(array_function_native, V8.ArrayFunctionNative) \
SC(for_in, V8.ForIn) \
SC(enum_cache_hits, V8.EnumCacheHits) \
SC(enum_cache_misses, V8.EnumCacheMisses) \
diff --git a/deps/v8/src/v8natives.js b/deps/v8/src/v8natives.js
index be92347768..2fecee80c0 100644
--- a/deps/v8/src/v8natives.js
+++ b/deps/v8/src/v8natives.js
@@ -276,6 +276,13 @@ function ObjectLookupSetter(name) {
}
+function ObjectKeys(obj) {
+ if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj))
+ throw MakeTypeError('object_keys_non_object', [obj]);
+ return %LocalKeys(obj);
+}
+
+
%SetCode($Object, function(x) {
if (%_IsConstructCall()) {
if (x == null) return this;
@@ -304,6 +311,9 @@ function SetupObject() {
"__defineSetter__", ObjectDefineSetter,
"__lookupSetter__", ObjectLookupSetter
));
+ InstallFunctions($Object, DONT_ENUM, $Array(
+ "keys", ObjectKeys
+ ));
}
SetupObject();
@@ -514,7 +524,7 @@ function FunctionSourceString(func) {
}
var source = %FunctionGetSourceCode(func);
- if (!IS_STRING(source)) {
+ if (!IS_STRING(source) || %FunctionIsBuiltin(func)) {
var name = %FunctionGetName(func);
if (name) {
// Mimic what KJS does.
@@ -524,12 +534,6 @@ function FunctionSourceString(func) {
}
}
- // Censor occurrences of internal calls. We do that for all
- // functions and don't cache under the assumption that people rarly
- // convert functions to strings. Note that we (apparently) can't
- // use regular expression literals in natives files.
- var regexp = ORIGINAL_REGEXP("%(\\w+\\()", "gm");
- if (source.match(regexp)) source = source.replace(regexp, "$1");
var name = %FunctionGetName(func);
return 'function ' + name + source;
}
diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc
index 3d4939b481..8b612de5a9 100644
--- a/deps/v8/src/version.cc
+++ b/deps/v8/src/version.cc
@@ -34,8 +34,8 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 1
#define MINOR_VERSION 3
-#define BUILD_NUMBER 11
-#define PATCH_LEVEL 1
+#define BUILD_NUMBER 13
+#define PATCH_LEVEL 0
#define CANDIDATE_VERSION false
// Define SONAME to have the SCons build the put a specific SONAME into the
diff --git a/deps/v8/src/x64/builtins-x64.cc b/deps/v8/src/x64/builtins-x64.cc
index 170a15b833..d399a88005 100644
--- a/deps/v8/src/x64/builtins-x64.cc
+++ b/deps/v8/src/x64/builtins-x64.cc
@@ -452,6 +452,22 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
}
+void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
+ // Just jump to the generic array code.
+ Code* code = Builtins::builtin(Builtins::ArrayCodeGeneric);
+ Handle<Code> array_code(code);
+ __ Jump(array_code, RelocInfo::CODE_TARGET);
+}
+
+
+void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
+ // Just jump to the generic construct code.
+ Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
+ Handle<Code> generic_construct_stub(code);
+ __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
+}
+
+
void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax: number of arguments
diff --git a/deps/v8/src/zone-inl.h b/deps/v8/src/zone-inl.h
index b3141a4810..121ba19b12 100644
--- a/deps/v8/src/zone-inl.h
+++ b/deps/v8/src/zone-inl.h
@@ -276,12 +276,19 @@ void ZoneSplayTree<C>::Splay(const Key& key) {
}
-template <typename Node, class Callback>
-static void DoForEach(Node* node, Callback* callback) {
- if (node == NULL) return;
- DoForEach<Node, Callback>(node->left(), callback);
- callback->Call(node->key(), node->value());
- DoForEach<Node, Callback>(node->right(), callback);
+template <typename Config> template <class Callback>
+void ZoneSplayTree<Config>::ForEach(Callback* callback) {
+ // Pre-allocate some space for tiny trees.
+ ZoneList<Node*> nodes_to_visit(10);
+ nodes_to_visit.Add(root_);
+ int pos = 0;
+ while (pos < nodes_to_visit.length()) {
+ Node* node = nodes_to_visit[pos++];
+ if (node == NULL) continue;
+ callback->Call(node->key(), node->value());
+ nodes_to_visit.Add(node->left());
+ nodes_to_visit.Add(node->right());
+ }
}
diff --git a/deps/v8/src/zone.h b/deps/v8/src/zone.h
index cdbab32821..4e4f1d7224 100644
--- a/deps/v8/src/zone.h
+++ b/deps/v8/src/zone.h
@@ -204,10 +204,6 @@ class ZoneScope BASE_EMBEDDED {
};
-template <typename Node, class Callback>
-static void DoForEach(Node* node, Callback* callback);
-
-
// A zone splay tree. The config type parameter encapsulates the
// different configurations of a concrete splay tree:
//
@@ -297,9 +293,7 @@ class ZoneSplayTree : public ZoneObject {
};
template <class Callback>
- void ForEach(Callback* c) {
- DoForEach<typename ZoneSplayTree<Config>::Node, Callback>(root_, c);
- }
+ void ForEach(Callback* callback);
private:
Node* root_;
diff --git a/deps/v8/test/cctest/SConscript b/deps/v8/test/cctest/SConscript
index fc4e01a425..91034034a1 100644
--- a/deps/v8/test/cctest/SConscript
+++ b/deps/v8/test/cctest/SConscript
@@ -45,6 +45,7 @@ SOURCES = {
'test-func-name-inference.cc',
'test-hashmap.cc',
'test-heap.cc',
+ 'test-heap-profiler.cc',
'test-list.cc',
'test-lock.cc',
'test-log.cc',
diff --git a/deps/v8/test/cctest/test-heap-profiler.cc b/deps/v8/test/cctest/test-heap-profiler.cc
new file mode 100644
index 0000000000..f8e5a6b755
--- /dev/null
+++ b/deps/v8/test/cctest/test-heap-profiler.cc
@@ -0,0 +1,330 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+//
+// Tests for heap profiler
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+
+#include "v8.h"
+#include "heap-profiler.h"
+#include "string-stream.h"
+#include "cctest.h"
+
+namespace i = v8::internal;
+using i::ClustersCoarser;
+using i::JSObjectsCluster;
+using i::JSObjectsRetainerTree;
+using i::JSObjectsClusterTree;
+using i::RetainerHeapProfile;
+
+
+static void CompileAndRunScript(const char *src) {
+ v8::Script::Compile(v8::String::New(src))->Run();
+}
+
+
+namespace {
+
+class ConstructorHeapProfileTestHelper : public i::ConstructorHeapProfile {
+ public:
+ ConstructorHeapProfileTestHelper()
+ : i::ConstructorHeapProfile(),
+ f_name_(i::Factory::NewStringFromAscii(i::CStrVector("F"))),
+ f_count_(0) {
+ }
+
+ void Call(const JSObjectsCluster& cluster,
+ const i::NumberAndSizeInfo& number_and_size) {
+ if (f_name_->Equals(cluster.constructor())) {
+ CHECK_EQ(f_count_, 0);
+ f_count_ = number_and_size.number();
+ CHECK_GT(f_count_, 0);
+ }
+ }
+
+ int f_count() { return f_count_; }
+
+ private:
+ i::Handle<i::String> f_name_;
+ int f_count_;
+};
+
+} // namespace
+
+
+TEST(ConstructorProfile) {
+ v8::HandleScope scope;
+ v8::Handle<v8::Context> env = v8::Context::New();
+ env->Enter();
+
+ CompileAndRunScript(
+ "function F() {} // A constructor\n"
+ "var f1 = new F();\n"
+ "var f2 = new F();\n");
+
+ ConstructorHeapProfileTestHelper cons_profile;
+ i::AssertNoAllocation no_alloc;
+ i::HeapIterator iterator;
+ while (iterator.has_next()) {
+ i::HeapObject* obj = iterator.next();
+ cons_profile.CollectStats(obj);
+ }
+ CHECK_EQ(0, cons_profile.f_count());
+ cons_profile.PrintStats();
+ CHECK_EQ(2, cons_profile.f_count());
+}
+
+
+static JSObjectsCluster AddHeapObjectToTree(
+ JSObjectsRetainerTree* tree,
+ i::String* constructor,
+ int instance,
+ JSObjectsCluster* ref1 = NULL,
+ JSObjectsCluster* ref2 = NULL,
+ JSObjectsCluster* ref3 = NULL) {
+ JSObjectsCluster o(constructor, reinterpret_cast<i::Object*>(instance));
+ JSObjectsClusterTree* o_tree = new JSObjectsClusterTree();
+ JSObjectsClusterTree::Locator o_loc;
+ if (ref1 != NULL) o_tree->Insert(*ref1, &o_loc);
+ if (ref2 != NULL) o_tree->Insert(*ref2, &o_loc);
+ if (ref3 != NULL) o_tree->Insert(*ref3, &o_loc);
+ JSObjectsRetainerTree::Locator loc;
+ tree->Insert(o, &loc);
+ loc.set_value(o_tree);
+ return o;
+}
+
+
+static inline void CheckEqualsHelper(const char* file, int line,
+ const char* expected_source,
+ const JSObjectsCluster& expected,
+ const char* value_source,
+ const JSObjectsCluster& value) {
+ if (JSObjectsCluster::Compare(expected, value) != 0) {
+ i::HeapStringAllocator allocator;
+ i::StringStream stream(&allocator);
+ stream.Add("# Expected: ");
+ expected.DebugPrint(&stream);
+ stream.Add("\n# Found: ");
+ value.DebugPrint(&stream);
+ V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n%s",
+ expected_source, value_source,
+ *stream.ToCString());
+ }
+}
+
+
+static inline void CheckNonEqualsHelper(const char* file, int line,
+ const char* expected_source,
+ const JSObjectsCluster& expected,
+ const char* value_source,
+ const JSObjectsCluster& value) {
+ if (JSObjectsCluster::Compare(expected, value) == 0) {
+ i::HeapStringAllocator allocator;
+ i::StringStream stream(&allocator);
+ stream.Add("# Expected: ");
+ expected.DebugPrint(&stream);
+ stream.Add("\n# Found: ");
+ value.DebugPrint(&stream);
+ V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n%s",
+ expected_source, value_source,
+ *stream.ToCString());
+ }
+}
+
+
+TEST(ClustersCoarserSimple) {
+ v8::HandleScope scope;
+ v8::Handle<v8::Context> env = v8::Context::New();
+ env->Enter();
+
+ i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
+
+ JSObjectsRetainerTree tree;
+ JSObjectsCluster function(i::Heap::function_class_symbol());
+ JSObjectsCluster a(*i::Factory::NewStringFromAscii(i::CStrVector("A")));
+ JSObjectsCluster b(*i::Factory::NewStringFromAscii(i::CStrVector("B")));
+
+ // o1 <- Function
+ JSObjectsCluster o1 =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100, &function);
+ // o2 <- Function
+ JSObjectsCluster o2 =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x200, &function);
+ // o3 <- A, B
+ JSObjectsCluster o3 =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &a, &b);
+ // o4 <- B, A
+ JSObjectsCluster o4 =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x400, &b, &a);
+ // o5 <- A, B, Function
+ JSObjectsCluster o5 =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x500,
+ &a, &b, &function);
+
+ ClustersCoarser coarser;
+ coarser.Process(&tree);
+
+ CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2));
+ CHECK_EQ(coarser.GetCoarseEquivalent(o3), coarser.GetCoarseEquivalent(o4));
+ CHECK_NE(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o3));
+ CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o5));
+}
+
+
+TEST(ClustersCoarserMultipleConstructors) {
+ v8::HandleScope scope;
+ v8::Handle<v8::Context> env = v8::Context::New();
+ env->Enter();
+
+ i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
+
+ JSObjectsRetainerTree tree;
+ JSObjectsCluster function(i::Heap::function_class_symbol());
+
+ // o1 <- Function
+ JSObjectsCluster o1 =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100, &function);
+ // a1 <- Function
+ JSObjectsCluster a1 =
+ AddHeapObjectToTree(&tree, i::Heap::Array_symbol(), 0x1000, &function);
+ // o2 <- Function
+ JSObjectsCluster o2 =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x200, &function);
+ // a2 <- Function
+ JSObjectsCluster a2 =
+ AddHeapObjectToTree(&tree, i::Heap::Array_symbol(), 0x2000, &function);
+
+ ClustersCoarser coarser;
+ coarser.Process(&tree);
+
+ CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2));
+ CHECK_EQ(coarser.GetCoarseEquivalent(a1), coarser.GetCoarseEquivalent(a2));
+}
+
+
+TEST(ClustersCoarserPathsTraversal) {
+ v8::HandleScope scope;
+ v8::Handle<v8::Context> env = v8::Context::New();
+ env->Enter();
+
+ i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
+
+ JSObjectsRetainerTree tree;
+
+ // On the following graph:
+ //
+ // p
+ // <- o21 <- o11 <-
+ // q o
+ // <- o22 <- o12 <-
+ // r
+ //
+ // we expect that coarser will deduce equivalences: p ~ q ~ r,
+ // o21 ~ o22, and o11 ~ o12.
+
+ JSObjectsCluster o =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100);
+ JSObjectsCluster o11 =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x110, &o);
+ JSObjectsCluster o12 =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x120, &o);
+ JSObjectsCluster o21 =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x210, &o11);
+ JSObjectsCluster o22 =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x220, &o12);
+ JSObjectsCluster p =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &o21);
+ JSObjectsCluster q =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x310, &o21, &o22);
+ JSObjectsCluster r =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x320, &o22);
+
+ ClustersCoarser coarser;
+ coarser.Process(&tree);
+
+ CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o));
+ CHECK_EQ(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(o12));
+ CHECK_EQ(coarser.GetCoarseEquivalent(o21), coarser.GetCoarseEquivalent(o22));
+ CHECK_NE(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(o21));
+ CHECK_EQ(coarser.GetCoarseEquivalent(p), coarser.GetCoarseEquivalent(q));
+ CHECK_EQ(coarser.GetCoarseEquivalent(q), coarser.GetCoarseEquivalent(r));
+ CHECK_NE(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(p));
+ CHECK_NE(coarser.GetCoarseEquivalent(o21), coarser.GetCoarseEquivalent(p));
+}
+
+
+namespace {
+
+class RetainerProfilePrinter : public RetainerHeapProfile::Printer {
+ public:
+ RetainerProfilePrinter() : stream_(&allocator_), lines_(100) {}
+
+ void PrintRetainers(const JSObjectsCluster& cluster,
+ const i::StringStream& retainers) {
+ cluster.Print(&stream_);
+ stream_.Add("%s", *(retainers.ToCString()));
+ stream_.Put('\0');
+ }
+
+ const char* GetRetainers(const char* constructor) {
+ FillLines();
+ const size_t cons_len = strlen(constructor);
+ for (int i = 0; i < lines_.length(); ++i) {
+ if (strncmp(constructor, lines_[i], cons_len) == 0 &&
+ lines_[i][cons_len] == ',') {
+ return lines_[i] + cons_len + 1;
+ }
+ }
+ return NULL;
+ }
+
+ private:
+ void FillLines() {
+ if (lines_.length() > 0) return;
+ stream_.Put('\0');
+ stream_str_ = stream_.ToCString();
+ const char* pos = *stream_str_;
+ while (pos != NULL && *pos != '\0') {
+ lines_.Add(pos);
+ pos = strchr(pos, '\0');
+ if (pos != NULL) ++pos;
+ }
+ }
+
+ i::HeapStringAllocator allocator_;
+ i::StringStream stream_;
+ i::SmartPointer<const char> stream_str_;
+ i::List<const char*> lines_;
+};
+
+} // namespace
+
+
+TEST(RetainerProfile) {
+ v8::HandleScope scope;
+ v8::Handle<v8::Context> env = v8::Context::New();
+ env->Enter();
+
+ CompileAndRunScript(
+ "function A() {}\n"
+ "function B(x) { this.x = x; }\n"
+ "function C(x) { this.x1 = x; this.x2 = x; }\n"
+ "var a = new A();\n"
+ "var b1 = new B(a), b2 = new B(a);\n"
+ "var c = new C(a);");
+
+ RetainerHeapProfile ret_profile;
+ i::AssertNoAllocation no_alloc;
+ i::HeapIterator iterator;
+ while (iterator.has_next()) {
+ i::HeapObject* obj = iterator.next();
+ ret_profile.CollectStats(obj);
+ }
+ RetainerProfilePrinter printer;
+ ret_profile.DebugPrintStats(&printer);
+ CHECK_EQ("(global property);1,B;2,C;2", printer.GetRetainers("A"));
+ CHECK_EQ("(global property);2", printer.GetRetainers("B"));
+ CHECK_EQ("(global property);1", printer.GetRetainers("C"));
+}
+
+#endif // ENABLE_LOGGING_AND_PROFILING
diff --git a/deps/v8/test/es5conform/README b/deps/v8/test/es5conform/README
new file mode 100644
index 0000000000..a88f4a368f
--- /dev/null
+++ b/deps/v8/test/es5conform/README
@@ -0,0 +1,14 @@
+This directory contains code for binding the es5conform test suite
+into the v8 test harness. To use the tests check out the es5conform
+tests from
+
+ https://es5conform.svn.codeplex.com/svn
+
+in revision 59101 as 'data' in this directory. Using later version
+may be possible but the tests are only known to pass (and indeed run)
+with that revision.
+
+If you do update to a newer revision you may have to change the test
+harness adapter code since it uses internal functionality from the
+harness that comes bundled with the tests. You will most likely also
+have to update the test expectation file.
diff --git a/deps/v8/test/es5conform/es5conform.status b/deps/v8/test/es5conform/es5conform.status
new file mode 100644
index 0000000000..49cffb2801
--- /dev/null
+++ b/deps/v8/test/es5conform/es5conform.status
@@ -0,0 +1,68 @@
+# 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.
+
+prefix es5conform
+def UNIMPLEMENTED = PASS || FAIL
+def FAIL_OK = FAIL, OKAY
+
+chapter07: UNIMPLEMENTED
+chapter08: UNIMPLEMENTED
+chapter10: UNIMPLEMENTED
+chapter11: UNIMPLEMENTED
+chapter12: UNIMPLEMENTED
+chapter13: UNIMPLEMENTED
+chapter14: UNIMPLEMENTED
+chapter15/15.1: UNIMPLEMENTED
+chapter15/15.2/15.2.3/15.2.3.1: UNIMPLEMENTED
+chapter15/15.2/15.2.3/15.2.3.2: UNIMPLEMENTED
+chapter15/15.2/15.2.3/15.2.3.3: UNIMPLEMENTED
+chapter15/15.2/15.2.3/15.2.3.4: UNIMPLEMENTED
+chapter15/15.2/15.2.3/15.2.3.5: UNIMPLEMENTED
+chapter15/15.2/15.2.3/15.2.3.6: UNIMPLEMENTED
+chapter15/15.2/15.2.3/15.2.3.7: UNIMPLEMENTED
+chapter15/15.2/15.2.3/15.2.3.8: UNIMPLEMENTED
+chapter15/15.2/15.2.3/15.2.3.9: UNIMPLEMENTED
+chapter15/15.2/15.2.3/15.2.3.10: UNIMPLEMENTED
+chapter15/15.2/15.2.3/15.2.3.11: UNIMPLEMENTED
+chapter15/15.2/15.2.3/15.2.3.12: UNIMPLEMENTED
+chapter15/15.2/15.2.3/15.2.3.13: UNIMPLEMENTED
+
+# Object.keys
+chapter15/15.2/15.2.3/15.2.3.14: PASS
+
+# We fail this because Object.keys returns numbers for element indices
+# rather than strings.
+chapter15/15.2/15.2.3/15.2.3.14/15.2.3.14-3-3: FAIL_OK
+
+chapter15/15.3: UNIMPLEMENTED
+chapter15/15.4: UNIMPLEMENTED
+chapter15/15.5: UNIMPLEMENTED
+chapter15/15.6: UNIMPLEMENTED
+chapter15/15.7: UNIMPLEMENTED
+chapter15/15.9: UNIMPLEMENTED
+chapter15/15.10: UNIMPLEMENTED
+chapter15/15.12: UNIMPLEMENTED
diff --git a/deps/v8/test/mjsunit/array-splice-webkit.js b/deps/v8/test/es5conform/harness-adapt.js
index 113a56a6ed..396d4ed978 100644
--- a/deps/v8/test/mjsunit/array-splice-webkit.js
+++ b/deps/v8/test/es5conform/harness-adapt.js
@@ -1,4 +1,4 @@
-// Copyright 2008 the V8 project authors. All rights reserved.
+// 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:
@@ -25,36 +25,50 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Simple splice tests based on webkit layout tests.
-var arr = ['a','b','c','d'];
-assertArrayEquals(['a','b','c','d'], arr);
-assertArrayEquals(['c','d'], arr.splice(2));
-assertArrayEquals(['a','b'], arr);
-assertArrayEquals(['a','b'], arr.splice(0));
-assertArrayEquals([], arr)
-
-arr = ['a','b','c','d'];
-assertEquals(undefined, arr.splice())
-assertArrayEquals(['a','b','c','d'], arr);
-assertArrayEquals(['a','b','c','d'], arr.splice(undefined))
-assertArrayEquals([], arr);
-
-arr = ['a','b','c','d'];
-assertArrayEquals(['a','b','c','d'], arr.splice(null))
-assertArrayEquals([], arr);
-
-arr = ['a','b','c','d'];
-assertArrayEquals([], arr.splice(100))
-assertArrayEquals(['a','b','c','d'], arr);
-assertArrayEquals(['d'], arr.splice(-1))
-assertArrayEquals(['a','b','c'], arr);
-
-assertArrayEquals([], arr.splice(2, undefined))
-assertArrayEquals([], arr.splice(2, null))
-assertArrayEquals([], arr.splice(2, -1))
-assertArrayEquals([], arr.splice(2, 0))
-assertArrayEquals(['a','b','c'], arr);
-assertArrayEquals(['c'], arr.splice(2, 100))
-assertArrayEquals(['a','b'], arr);
+var global = this;
+function ES5Error(ut) {
+ this.ut = ut;
+}
+ES5Error.prototype.toString = function () {
+ return this.ut.res;
+};
+
+// The harness uses the IE specific .description property of exceptions but
+// that's nothing we can't hack our way around.
+Error.prototype.__defineGetter__('description', function () {
+ return this.message;
+});
+
+function TestHarness() {
+ sth.call(this, global);
+ this._testResults = []
+}
+
+// Borrow sth's registerTest method.
+TestHarness.prototype.registerTest = sth.prototype.registerTest;
+
+// Drop the before/after stuff, just run the test.
+TestHarness.prototype.startTesting = function () {
+ sth.prototype.run.call(this);
+ this.report();
+};
+
+TestHarness.prototype.report = function () {
+ for (var i = 0; i < this._testResults.length; i++) {
+ var ut = this._testResults[i];
+ // We don't fail on preconditions. Yet.
+ if (ut.res == "Precondition failed")
+ continue;
+ if (ut.res != 'pass')
+ throw new ES5Error(ut);
+ }
+};
+
+TestHarness.prototype.startingTest = function (ut) {
+ this.currentTest = ut;
+ this._testResults.push(ut);
+};
+
+var ES5Harness = new TestHarness();
diff --git a/deps/v8/test/es5conform/testcfg.py b/deps/v8/test/es5conform/testcfg.py
new file mode 100644
index 0000000000..d1f23aa312
--- /dev/null
+++ b/deps/v8/test/es5conform/testcfg.py
@@ -0,0 +1,108 @@
+# Copyright 2008 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+import test
+import os
+from os.path import join, exists
+
+
+HARNESS_FILES = ['sth.js']
+
+
+class ES5ConformTestCase(test.TestCase):
+
+ def __init__(self, filename, path, context, root, mode, framework):
+ super(ES5ConformTestCase, self).__init__(context, path)
+ self.filename = filename
+ self.mode = mode
+ self.framework = framework
+ self.root = root
+
+ def IsNegative(self):
+ return self.filename.endswith('-n.js')
+
+ def GetLabel(self):
+ return "%s es5conform %s" % (self.mode, self.GetName())
+
+ def IsFailureOutput(self, output):
+ if output.exit_code != 0:
+ return True
+ return 'FAILED!' in output.stdout
+
+ def GetCommand(self):
+ result = [self.context.GetVm(self.mode)]
+ result += ['-e', 'var window = this']
+ result += self.framework
+ result.append(self.filename)
+ result += ['-e', 'ES5Harness.startTesting()']
+ return result
+
+ def GetName(self):
+ return self.path[-1]
+
+ def GetSource(self):
+ return open(self.filename).read()
+
+
+class ES5ConformTestConfiguration(test.TestConfiguration):
+
+ def __init__(self, context, root):
+ super(ES5ConformTestConfiguration, self).__init__(context, root)
+
+ def ListTests(self, current_path, path, mode):
+ tests = []
+ current_root = join(self.root, 'data', 'TestCases')
+ harness = []
+ harness += [join(self.root, 'data', 'SimpleTestHarness', f) for f in HARNESS_FILES]
+ harness += [join(self.root, 'harness-adapt.js')]
+ for root, dirs, files in os.walk(current_root):
+ for dotted in [x for x in dirs if x.startswith('.')]:
+ dirs.remove(dotted)
+ root_path = root[len(self.root):].split(os.path.sep)
+ root_path = current_path + [x for x in root_path if x]
+ for file in files:
+ if file.endswith('.js'):
+ full_path = root_path + [file[:-3]]
+ full_path = [x for x in full_path if not (x in ['data', 'TestCases'])]
+ if self.Contains(path, full_path):
+ test = ES5ConformTestCase(join(root, file), full_path, self.context,
+ self.root, mode, harness)
+ tests.append(test)
+ return tests
+
+ def GetBuildRequirements(self):
+ return ['sample', 'sample=shell']
+
+ def GetTestStatus(self, sections, defs):
+ status_file = join(self.root, 'es5conform.status')
+ if exists(status_file):
+ test.ReadConfigurationInto(status_file, sections, defs)
+
+
+def GetConfiguration(context, root):
+ return ES5ConformTestConfiguration(context, root)
diff --git a/deps/v8/test/mjsunit/arguments-enum.js b/deps/v8/test/mjsunit/arguments-enum.js
index f76240ff1b..3aee918af1 100644
--- a/deps/v8/test/mjsunit/arguments-enum.js
+++ b/deps/v8/test/mjsunit/arguments-enum.js
@@ -42,11 +42,11 @@ function setArgumentCount() {
}
assertEquals(0, countArguments());
-assertEquals(0, countArguments(1));
-assertEquals(0, countArguments(1, 2));
-assertEquals(0, countArguments(1, 2, 3, 4, 5));
+assertEquals(1, countArguments(1));
+assertEquals(2, countArguments(1, 2));
+assertEquals(5, countArguments(1, 2, 3, 4, 5));
-assertEquals(0, setArgumentCount());
-assertEquals(0, setArgumentCount(1));
-assertEquals(0, setArgumentCount(1, 2));
-assertEquals(0, setArgumentCount(1, 2, 3, 4, 5));
+assertEquals(2, setArgumentCount());
+assertEquals(3, setArgumentCount(1));
+assertEquals(4, setArgumentCount(1, 2));
+assertEquals(7, setArgumentCount(1, 2, 3, 4, 5));
diff --git a/deps/v8/test/mjsunit/array-constructor.js b/deps/v8/test/mjsunit/array-constructor.js
new file mode 100644
index 0000000000..063ccde583
--- /dev/null
+++ b/deps/v8/test/mjsunit/array-constructor.js
@@ -0,0 +1,119 @@
+// 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.
+
+
+var loop_count = 5
+
+
+for (var i = 0; i < loop_count; i++) {
+ var a = new Array();
+ var b = Array();
+ assertEquals(0, a.length);
+ assertEquals(0, b.length);
+ for (var k = 0; k < 10; k++) {
+ assertEquals('undefined', typeof a[k]);
+ assertEquals('undefined', typeof b[k]);
+ }
+}
+
+
+for (var i = 0; i < loop_count; i++) {
+ for (var j = 0; j < 100; j++) {
+ var a = new Array(j);
+ var b = Array(j);
+ assertEquals(j, a.length);
+ assertEquals(j, b.length);
+ for (var k = 0; k < j; k++) {
+ assertEquals('undefined', typeof a[k]);
+ assertEquals('undefined', typeof b[k]);
+ }
+ }
+}
+
+
+for (var i = 0; i < loop_count; i++) {
+ a = new Array(0, 1);
+ assertArrayEquals([0, 1], a);
+ a = new Array(0, 1, 2);
+ assertArrayEquals([0, 1, 2], a);
+ a = new Array(0, 1, 2, 3);
+ assertArrayEquals([0, 1, 2, 3], a);
+ a = new Array(0, 1, 2, 3, 4);
+ assertArrayEquals([0, 1, 2, 3, 4], a);
+ a = new Array(0, 1, 2, 3, 4, 5);
+ assertArrayEquals([0, 1, 2, 3, 4, 5], a);
+ a = new Array(0, 1, 2, 3, 4, 5, 6);
+ assertArrayEquals([0, 1, 2, 3, 4, 5, 6], a);
+ a = new Array(0, 1, 2, 3, 4, 5, 6, 7);
+ assertArrayEquals([0, 1, 2, 3, 4, 5, 6, 7], a);
+ a = new Array(0, 1, 2, 3, 4, 5, 6, 7, 8);
+ assertArrayEquals([0, 1, 2, 3, 4, 5, 6, 7, 8], a);
+ a = new Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+ assertArrayEquals([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], a);
+}
+
+
+function innerArrayLiteral(n) {
+ var a = new Array(n);
+ for (var i = 0; i < n; i++) {
+ a[i] = i * 2 + 7;
+ }
+ return a.join();
+}
+
+
+function testConstructOfSizeSize(n) {
+ var str = innerArrayLiteral(n);
+ var a = eval('[' + str + ']');
+ var b = eval('new Array(' + str + ')')
+ var c = eval('Array(' + str + ')')
+ assertEquals(n, a.length);
+ assertArrayEquals(a, b);
+ assertArrayEquals(a, c);
+}
+
+
+for (var i = 0; i < loop_count; i++) {
+ // JSObject::kInitialMaxFastElementArray is 10000.
+ for (var j = 1000; j < 12000; j += 1000) {
+ testConstructOfSizeSize(j);
+ }
+}
+
+
+for (var i = 0; i < loop_count; i++) {
+ assertArrayEquals(['xxx'], new Array('xxx'));
+ assertArrayEquals(['xxx'], Array('xxx'));
+ assertArrayEquals([true], new Array(true));
+ assertArrayEquals([false], Array(false));
+ assertArrayEquals([{a:1}], new Array({a:1}));
+ assertArrayEquals([{b:2}], Array({b:2}));
+}
+
+
+assertThrows('new Array(3.14)');
+assertThrows('Array(2.72)');
diff --git a/deps/v8/test/mjsunit/mjsunit.status b/deps/v8/test/mjsunit/mjsunit.status
index 13e69ae351..0b069ccbe9 100644
--- a/deps/v8/test/mjsunit/mjsunit.status
+++ b/deps/v8/test/mjsunit/mjsunit.status
@@ -41,6 +41,7 @@ big-object-literal: PASS, SKIP if ($arch == arm)
# Slow tests which times out in debug mode.
try: PASS, SKIP if $mode == debug
debug-scripts-request: PASS, SKIP if $mode == debug
+array-constructor: PASS, SKIP if $mode == debug
# Flaky test that can hit compilation-time stack overflow in debug mode.
unicode-test: PASS, (PASS || FAIL) if $mode == debug
diff --git a/deps/v8/test/mjsunit/testcfg.py b/deps/v8/test/mjsunit/testcfg.py
index 97924c8de0..e3f3fcd940 100644
--- a/deps/v8/test/mjsunit/testcfg.py
+++ b/deps/v8/test/mjsunit/testcfg.py
@@ -112,8 +112,9 @@ class MjsunitTestConfiguration(test.TestConfiguration):
mjsunit = [current_path + [t] for t in self.Ls(self.root)]
regress = [current_path + ['regress', t] for t in self.Ls(join(self.root, 'regress'))]
bugs = [current_path + ['bugs', t] for t in self.Ls(join(self.root, 'bugs'))]
+ third_party = [current_path + ['third_party', t] for t in self.Ls(join(self.root, 'third_party'))]
tools = [current_path + ['tools', t] for t in self.Ls(join(self.root, 'tools'))]
- all_tests = mjsunit + regress + bugs + tools
+ all_tests = mjsunit + regress + bugs + third_party + tools
result = []
for test in all_tests:
if self.Contains(path, test):
diff --git a/deps/v8/test/mjsunit/third_party/array-splice-webkit.js b/deps/v8/test/mjsunit/third_party/array-splice-webkit.js
new file mode 100644
index 0000000000..b676a7c165
--- /dev/null
+++ b/deps/v8/test/mjsunit/third_party/array-splice-webkit.js
@@ -0,0 +1,62 @@
+// Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// 2. 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.
+//
+// 3. Neither the name of the copyright holder(s) nor the names of any
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Simple splice tests based on webkit layout tests.
+var arr = ['a','b','c','d'];
+assertArrayEquals(['a','b','c','d'], arr);
+assertArrayEquals(['c','d'], arr.splice(2));
+assertArrayEquals(['a','b'], arr);
+assertArrayEquals(['a','b'], arr.splice(0));
+assertArrayEquals([], arr)
+
+arr = ['a','b','c','d'];
+assertEquals(undefined, arr.splice())
+assertArrayEquals(['a','b','c','d'], arr);
+assertArrayEquals(['a','b','c','d'], arr.splice(undefined))
+assertArrayEquals([], arr);
+
+arr = ['a','b','c','d'];
+assertArrayEquals(['a','b','c','d'], arr.splice(null))
+assertArrayEquals([], arr);
+
+arr = ['a','b','c','d'];
+assertArrayEquals([], arr.splice(100))
+assertArrayEquals(['a','b','c','d'], arr);
+assertArrayEquals(['d'], arr.splice(-1))
+assertArrayEquals(['a','b','c'], arr);
+
+assertArrayEquals([], arr.splice(2, undefined))
+assertArrayEquals([], arr.splice(2, null))
+assertArrayEquals([], arr.splice(2, -1))
+assertArrayEquals([], arr.splice(2, 0))
+assertArrayEquals(['a','b','c'], arr);
+assertArrayEquals(['c'], arr.splice(2, 100))
+assertArrayEquals(['a','b'], arr);
diff --git a/deps/v8/test/mjsunit/third_party/object-keys.js b/deps/v8/test/mjsunit/third_party/object-keys.js
new file mode 100644
index 0000000000..7486b8fb8d
--- /dev/null
+++ b/deps/v8/test/mjsunit/third_party/object-keys.js
@@ -0,0 +1,66 @@
+// Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// 2. 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.
+//
+// 3. Neither the name of the copyright holder(s) nor the names of any
+// 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.
+
+// Based on LayoutTests/fast/js/Object-keys.html
+
+assertThrows(function () { Object.keys(2) }, TypeError);
+assertThrows(function () { Object.keys("foo") }, TypeError);
+assertThrows(function () { Object.keys(null) }, TypeError);
+assertThrows(function () { Object.keys(undefined) }, TypeError);
+
+assertEquals(Object.keys({}), []);
+assertEquals(Object.keys({a:null}), ['a']);
+assertEquals(Object.keys({a:null, b:null}), ['a', 'b']);
+assertEquals(Object.keys({b:null, a:null}), ['b', 'a']);
+assertEquals(Object.keys([]), []);
+assertEquals(Object.keys([null]), ['0']);
+assertEquals(Object.keys([null,null]), ['0', '1']);
+assertEquals(Object.keys([null,null,,,,null]), ['0', '1', '5']);
+assertEquals(Object.keys({__proto__:{a:null}}), []);
+assertEquals(Object.keys({__proto__:[1,2,3]}), []);
+var x = [];
+x.__proto__ = [1, 2, 3];
+assertEquals(Object.keys(x), []);
+assertEquals(Object.keys(function () {}), []);
+
+function argsTest(a, b, c) {
+ assertEquals([0, 1, 2], Object.keys(arguments));
+}
+
+argsTest(1, 2, 3);
+
+var literal = {a: 1, b: 2, c: 3};
+var keysBefore = Object.keys(literal);
+assertEquals(['a', 'b', 'c'], keysBefore);
+keysBefore[0] = 'x';
+var keysAfter = Object.keys(literal);
+assertEquals(['a', 'b', 'c'], keysAfter);
+assertEquals(['x', 'b', 'c'], keysBefore);
diff --git a/deps/v8/test/mjsunit/regexp-pcre.js b/deps/v8/test/mjsunit/third_party/regexp-pcre.js
index dcb1b320fd..dcb1b320fd 100644
--- a/deps/v8/test/mjsunit/regexp-pcre.js
+++ b/deps/v8/test/mjsunit/third_party/regexp-pcre.js
diff --git a/deps/v8/test/mozilla/mozilla.status b/deps/v8/test/mozilla/mozilla.status
index 9793dc8318..c92bfa6bd9 100644
--- a/deps/v8/test/mozilla/mozilla.status
+++ b/deps/v8/test/mozilla/mozilla.status
@@ -217,6 +217,8 @@ js1_5/Function/regress-338121-01: FAIL_OK
js1_5/Function/regress-338121-02: FAIL_OK
js1_5/Function/regress-338121-03: FAIL_OK
+# Expectes 'prototype' property of functions to be enumerable.
+js1_5/Function/10.1.6-01: FAIL_OK
# Length of objects whose prototype chain includes a function
ecma_3/Function/regress-313570: FAIL_OK
@@ -567,11 +569,6 @@ js1_5/Array/regress-350256-02: FAIL
ecma_3/Function/regress-137181: FAIL
-# Tests that rely on specific details of function decompilation or
-# print strings for errors. Non-ECMA behavior.
-js1_4/Regress/function-003: FAIL
-
-
# 'export' and 'import' are not keywords in V8.
ecma_2/Exceptions/lexical-010: FAIL
ecma_2/Exceptions/lexical-022: FAIL
diff --git a/deps/v8/tools/gyp/v8.gyp b/deps/v8/tools/gyp/v8.gyp
index 22a15e2460..8af8f22bef 100644
--- a/deps/v8/tools/gyp/v8.gyp
+++ b/deps/v8/tools/gyp/v8.gyp
@@ -279,6 +279,8 @@
'../../src/heap-inl.h',
'../../src/heap.cc',
'../../src/heap.h',
+ '../../src/heap-profiler.cc',
+ '../../src/heap-profiler.h',
'../../src/ic-inl.h',
'../../src/ic.cc',
'../../src/ic.h',
diff --git a/deps/v8/tools/run-valgrind.py b/deps/v8/tools/run-valgrind.py
index 8a0869cbaa..49c1b70312 100755
--- a/deps/v8/tools/run-valgrind.py
+++ b/deps/v8/tools/run-valgrind.py
@@ -58,7 +58,7 @@ if code != 0:
# have any definitely, indirectly, and possibly lost bytes.
LEAK_RE = r"(?:definitely|indirectly|possibly) lost: "
LEAK_LINE_MATCHER = re.compile(LEAK_RE)
-LEAK_OKAY_MATCHER = re.compile(r"lost: 0 bytes in 0 blocks.")
+LEAK_OKAY_MATCHER = re.compile(r"lost: 0 bytes in 0 blocks")
leaks = []
for line in errors:
if LEAK_LINE_MATCHER.search(line):
diff --git a/deps/v8/tools/v8.xcodeproj/project.pbxproj b/deps/v8/tools/v8.xcodeproj/project.pbxproj
index 79ece72d7b..2d386811e1 100644
--- a/deps/v8/tools/v8.xcodeproj/project.pbxproj
+++ b/deps/v8/tools/v8.xcodeproj/project.pbxproj
@@ -207,6 +207,8 @@
89F23C9F0E78D604006B2466 /* simulator-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF17D0E719B8F00D62E90 /* simulator-arm.cc */; };
89F23CA00E78D609006B2466 /* stub-cache-arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF18A0E719B8F00D62E90 /* stub-cache-arm.cc */; };
89FB0E3A0F8E533F00B04B3C /* d8-posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = 89FB0E360F8E531900B04B3C /* d8-posix.cc */; };
+ 9F11D9A0105AF0A300EBE5B2 /* heap-profiler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F11D99E105AF0A300EBE5B2 /* heap-profiler.cc */; };
+ 9F11D9A1105AF0A300EBE5B2 /* heap-profiler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F11D99E105AF0A300EBE5B2 /* heap-profiler.cc */; };
9F4B7B890FCC877A00DC4117 /* log-utils.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F4B7B870FCC877A00DC4117 /* log-utils.cc */; };
9F4B7B8A0FCC877A00DC4117 /* log-utils.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F4B7B870FCC877A00DC4117 /* log-utils.cc */; };
9F92FAA90F8F28AD0089F02C /* func-name-inferrer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9F92FAA70F8F28AD0089F02C /* func-name-inferrer.cc */; };
@@ -533,6 +535,8 @@
89F23C950E78D5B6006B2466 /* v8_shell-arm */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "v8_shell-arm"; sourceTree = BUILT_PRODUCTS_DIR; };
89FB0E360F8E531900B04B3C /* d8-posix.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "d8-posix.cc"; path = "../src/d8-posix.cc"; sourceTree = "<group>"; };
89FB0E370F8E531900B04B3C /* d8-windows.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "d8-windows.cc"; path = "../src/d8-windows.cc"; sourceTree = "<group>"; };
+ 9F11D99E105AF0A300EBE5B2 /* heap-profiler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "heap-profiler.cc"; sourceTree = "<group>"; };
+ 9F11D99F105AF0A300EBE5B2 /* heap-profiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "heap-profiler.h"; sourceTree = "<group>"; };
9F4B7B870FCC877A00DC4117 /* log-utils.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "log-utils.cc"; sourceTree = "<group>"; };
9F4B7B880FCC877A00DC4117 /* log-utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "log-utils.h"; sourceTree = "<group>"; };
9F92FAA70F8F28AD0089F02C /* func-name-inferrer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "func-name-inferrer.cc"; sourceTree = "<group>"; };
@@ -626,7 +630,6 @@
897FF0D70E719AB300D62E90 /* C++ */ = {
isa = PBXGroup;
children = (
- 22A76C900FF259E600FDC694 /* log-inl.h */,
897FF0F60E719B8F00D62E90 /* accessors.cc */,
897FF0F70E719B8F00D62E90 /* accessors.h */,
897FF0F80E719B8F00D62E90 /* allocation.cc */,
@@ -725,6 +728,8 @@
897FF1460E719B8F00D62E90 /* heap-inl.h */,
897FF1470E719B8F00D62E90 /* heap.cc */,
897FF1480E719B8F00D62E90 /* heap.h */,
+ 9F11D99E105AF0A300EBE5B2 /* heap-profiler.cc */,
+ 9F11D99F105AF0A300EBE5B2 /* heap-profiler.h */,
897FF1490E719B8F00D62E90 /* ic-arm.cc */,
897FF14A0E719B8F00D62E90 /* ic-ia32.cc */,
897FF14B0E719B8F00D62E90 /* ic-inl.h */,
@@ -742,6 +747,7 @@
897FF1510E719B8F00D62E90 /* list.h */,
897FF1520E719B8F00D62E90 /* log.cc */,
897FF1530E719B8F00D62E90 /* log.h */,
+ 22A76C900FF259E600FDC694 /* log-inl.h */,
9F4B7B870FCC877A00DC4117 /* log-utils.cc */,
9F4B7B880FCC877A00DC4117 /* log-utils.h */,
897FF1540E719B8F00D62E90 /* macro-assembler-arm.cc */,
@@ -1201,6 +1207,7 @@
89A88E2E0E71A6D60043BA31 /* zone.cc in Sources */,
9F4B7B890FCC877A00DC4117 /* log-utils.cc in Sources */,
8981F6001010501900D1520E /* frame-element.cc in Sources */,
+ 9F11D9A0105AF0A300EBE5B2 /* heap-profiler.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1306,6 +1313,7 @@
89F23C820E78D5B2006B2466 /* zone.cc in Sources */,
9F4B7B8A0FCC877A00DC4117 /* log-utils.cc in Sources */,
8981F6011010502800D1520E /* frame-element.cc in Sources */,
+ 9F11D9A1105AF0A300EBE5B2 /* heap-profiler.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/deps/v8/tools/visual_studio/v8_base.vcproj b/deps/v8/tools/visual_studio/v8_base.vcproj
index 421cc7ce95..f402e8b6e5 100644
--- a/deps/v8/tools/visual_studio/v8_base.vcproj
+++ b/deps/v8/tools/visual_studio/v8_base.vcproj
@@ -489,6 +489,14 @@
>
</File>
<File
+ RelativePath="..\..\src\heap-profiler.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\heap-profiler.h"
+ >
+ </File>
+ <File
RelativePath="..\..\src\ia32\ic-ia32.cc"
>
</File>
diff --git a/deps/v8/tools/visual_studio/v8_base_arm.vcproj b/deps/v8/tools/visual_studio/v8_base_arm.vcproj
index ee8e339920..f0ba07a674 100644
--- a/deps/v8/tools/visual_studio/v8_base_arm.vcproj
+++ b/deps/v8/tools/visual_studio/v8_base_arm.vcproj
@@ -497,6 +497,14 @@
>
</File>
<File
+ RelativePath="..\..\src\heap-profiler.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\heap-profiler.h"
+ >
+ </File>
+ <File
RelativePath="..\..\src\arm\ic-arm.cc"
>
</File>
diff --git a/deps/v8/tools/visual_studio/v8_base_x64.vcproj b/deps/v8/tools/visual_studio/v8_base_x64.vcproj
index 1e27824629..d403da0ecd 100644
--- a/deps/v8/tools/visual_studio/v8_base_x64.vcproj
+++ b/deps/v8/tools/visual_studio/v8_base_x64.vcproj
@@ -489,6 +489,14 @@
>
</File>
<File
+ RelativePath="..\..\src\heap-profiler.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\heap-profiler.h"
+ >
+ </File>
+ <File
RelativePath="..\..\src\x64\ic-x64.cc"
>
</File>
diff --git a/deps/v8/tools/visual_studio/v8_cctest.vcproj b/deps/v8/tools/visual_studio/v8_cctest.vcproj
index ec078894ff..d1cf2e84cf 100644
--- a/deps/v8/tools/visual_studio/v8_cctest.vcproj
+++ b/deps/v8/tools/visual_studio/v8_cctest.vcproj
@@ -198,6 +198,10 @@
>
</File>
<File
+ RelativePath="..\..\test\cctest\test-heap-profiler.cc"
+ >
+ </File>
+ <File
RelativePath="..\..\test\cctest\test-lock.cc"
>
</File>
diff --git a/deps/v8/tools/visual_studio/v8_cctest_arm.vcproj b/deps/v8/tools/visual_studio/v8_cctest_arm.vcproj
index bd49f3b062..968d13472e 100644
--- a/deps/v8/tools/visual_studio/v8_cctest_arm.vcproj
+++ b/deps/v8/tools/visual_studio/v8_cctest_arm.vcproj
@@ -194,6 +194,10 @@
>
</File>
<File
+ RelativePath="..\..\test\cctest\test-heap-profiler.cc"
+ >
+ </File>
+ <File
RelativePath="..\..\test\cctest\test-lock.cc"
>
</File>
diff --git a/deps/v8/tools/visual_studio/v8_cctest_x64.vcproj b/deps/v8/tools/visual_studio/v8_cctest_x64.vcproj
index d0fbac63ae..78db1a4aa9 100644
--- a/deps/v8/tools/visual_studio/v8_cctest_x64.vcproj
+++ b/deps/v8/tools/visual_studio/v8_cctest_x64.vcproj
@@ -200,6 +200,10 @@
>
</File>
<File
+ RelativePath="..\..\test\cctest\test-heap-profiler.cc"
+ >
+ </File>
+ <File
RelativePath="..\..\test\cctest\test-lock.cc"
>
</File>