Revision: 12934
Author:
mvst...@chromium.org
Date: Mon Nov 12 06:53:34 2012
Log: Version 3.15.2
Function::GetScriptOrigin supplies sourceURL when script name is not
available. (Chromium issue 159413)
Made formatting error message side-effect-free. (issue 2398)
Fixed length check in JSON.stringify. (Chromium issue 160010)
ES6: Added support for Set and Map clear method (issue 2400)
Fixed slack tracking when instance prototype changes. (Chromium issue
157019)
Fixed disabling of code flusher while marking. (Chromium issue 159140)
Added a test case for object grouping in a scavenger GC (issue 2077)
Support shared library build of Android for v8. (Chromium issue 158821)
ES6: Added support for size to Set and Map (issue 2395)
Performance and stability improvements on all platforms.
http://code.google.com/p/v8/source/detail?r=12934
Added:
/trunk/test/cctest/test-object-observe.cc
/trunk/test/mjsunit/error-accessors.js
/trunk/test/mjsunit/regress/regress-2398.js
/trunk/test/mjsunit/regress/regress-crbug-157019.js
/trunk/test/mjsunit/regress/regress-crbug-160010.js
Modified:
/trunk/.gitignore
/trunk/ChangeLog
/trunk/include/v8.h
/trunk/src/accessors.cc
/trunk/src/api.cc
/trunk/src/arm/assembler-arm-inl.h
/trunk/src/arm/assembler-arm.cc
/trunk/src/arm/assembler-arm.h
/trunk/src/arm/builtins-arm.cc
/trunk/src/arm/code-stubs-arm.cc
/trunk/src/arm/codegen-arm.cc
/trunk/src/arm/codegen-arm.h
/trunk/src/arm/full-codegen-arm.cc
/trunk/src/arm/lithium-arm.cc
/trunk/src/arm/lithium-codegen-arm.cc
/trunk/src/arm/macro-assembler-arm.cc
/trunk/src/arm/macro-assembler-arm.h
/trunk/src/arm/simulator-arm.cc
/trunk/src/arm/stub-cache-arm.cc
/trunk/src/array.js
/trunk/src/assembler.cc
/trunk/src/assembler.h
/trunk/src/bootstrapper.cc
/trunk/src/builtins.cc
/trunk/src/builtins.h
/trunk/src/code-stubs.h
/trunk/src/collection.js
/trunk/src/compiler.cc
/trunk/src/contexts.h
/trunk/src/debug.cc
/trunk/src/deoptimizer.cc
/trunk/src/deoptimizer.h
/trunk/src/elements.cc
/trunk/src/elements.h
/trunk/src/flag-definitions.h
/trunk/src/global-handles.cc
/trunk/src/global-handles.h
/trunk/src/handles.cc
/trunk/src/handles.h
/trunk/src/heap.cc
/trunk/src/heap.h
/trunk/src/ia32/assembler-ia32-inl.h
/trunk/src/ia32/assembler-ia32.cc
/trunk/src/ia32/assembler-ia32.h
/trunk/src/ia32/builtins-ia32.cc
/trunk/src/ia32/code-stubs-ia32.cc
/trunk/src/ia32/codegen-ia32.cc
/trunk/src/ia32/codegen-ia32.h
/trunk/src/ia32/full-codegen-ia32.cc
/trunk/src/ia32/lithium-codegen-ia32.cc
/trunk/src/ia32/lithium-ia32.cc
/trunk/src/ia32/lithium-ia32.h
/trunk/src/ia32/macro-assembler-ia32.cc
/trunk/src/ia32/stub-cache-ia32.cc
/trunk/src/ic.cc
/trunk/src/incremental-marking.cc
/trunk/src/incremental-marking.h
/trunk/src/isolate.cc
/trunk/src/isolate.h
/trunk/src/json-stringifier.h
/trunk/src/liveedit.cc
/trunk/src/mark-compact.cc
/trunk/src/mark-compact.h
/trunk/src/messages.cc
/trunk/src/messages.js
/trunk/src/mips/assembler-mips.cc
/trunk/src/mips/assembler-mips.h
/trunk/src/mips/code-stubs-mips.cc
/trunk/src/mips/lithium-codegen-mips.cc
/trunk/src/mips/lithium-codegen-mips.h
/trunk/src/mips/lithium-mips.cc
/trunk/src/mips/lithium-mips.h
/trunk/src/mips/macro-assembler-mips.cc
/trunk/src/mips/stub-cache-mips.cc
/trunk/src/object-observe.js
/trunk/src/objects-inl.h
/trunk/src/objects-visiting-inl.h
/trunk/src/objects-visiting.cc
/trunk/src/objects-visiting.h
/trunk/src/objects.cc
/trunk/src/objects.h
/trunk/src/property.h
/trunk/src/runtime.cc
/trunk/src/runtime.h
/trunk/src/serialize.cc
/trunk/src/v8.cc
/trunk/src/v8natives.js
/trunk/src/version.cc
/trunk/src/x64/assembler-x64-inl.h
/trunk/src/x64/assembler-x64.cc
/trunk/src/x64/assembler-x64.h
/trunk/src/x64/builtins-x64.cc
/trunk/src/x64/code-stubs-x64.cc
/trunk/src/x64/codegen-x64.cc
/trunk/src/x64/codegen-x64.h
/trunk/src/x64/full-codegen-x64.cc
/trunk/src/x64/lithium-codegen-x64.cc
/trunk/src/x64/lithium-codegen-x64.h
/trunk/src/x64/lithium-x64.cc
/trunk/src/x64/lithium-x64.h
/trunk/src/x64/macro-assembler-x64.cc
/trunk/src/x64/stub-cache-x64.cc
/trunk/test/cctest/cctest.gyp
/trunk/test/cctest/test-api.cc
/trunk/test/cctest/test-heap.cc
/trunk/test/mjsunit/harmony/collections.js
/trunk/test/mjsunit/harmony/object-observe.js
/trunk/test/mjsunit/harmony/proxies.js
/trunk/test/mjsunit/json-recursive.js
/trunk/test/mjsunit/mjsunit.status
/trunk/tools/gen-postmortem-metadata.py
/trunk/tools/gyp/v8.gyp
=======================================
--- /dev/null
+++ /trunk/test/cctest/test-object-observe.cc Mon Nov 12 06:53:34 2012
@@ -0,0 +1,196 @@
+// Copyright 2012 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 "cctest.h"
+
+using namespace v8;
+
+namespace {
+// Need to create a new isolate when FLAG_harmony_observation is on.
+class HarmonyIsolate {
+ public:
+ HarmonyIsolate() {
+ i::FLAG_harmony_observation = true;
+ isolate_ = Isolate::New();
+ isolate_->Enter();
+ }
+
+ ~HarmonyIsolate() {
+ isolate_->Exit();
+ isolate_->Dispose();
+ }
+
+ private:
+ Isolate* isolate_;
+};
+}
+
+TEST(PerIsolateState) {
+ HarmonyIsolate isolate;
+ HandleScope scope;
+ LocalContext context1;
+ CompileRun(
+ "var count = 0;"
+ "var calls = 0;"
+ "var observer = function(records) { count = records.length; calls++
};"
+ "var obj = {};"
+ "Object.observe(obj, observer);");
+ Handle<Value> observer = CompileRun("observer");
+ Handle<Value> obj = CompileRun("obj");
+ Handle<Value> notify_fun1 = CompileRun(
+ "(function() { obj.foo = 'bar'; })");
+ Handle<Value> notify_fun2;
+ {
+ LocalContext context2;
+ context2->Global()->Set(String::New("obj"), obj);
+ notify_fun2 = CompileRun(
+ "(function() { obj.foo = 'baz'; })");
+ }
+ Handle<Value> notify_fun3;
+ {
+ LocalContext context3;
+ context3->Global()->Set(String::New("obj"), obj);
+ notify_fun3 = CompileRun(
+ "(function() { obj.foo = 'bat'; })");
+ }
+ {
+ LocalContext context4;
+ context4->Global()->Set(String::New("observer"), observer);
+ context4->Global()->Set(String::New("fun1"), notify_fun1);
+ context4->Global()->Set(String::New("fun2"), notify_fun2);
+ context4->Global()->Set(String::New("fun3"), notify_fun3);
+ CompileRun("fun1(); fun2(); fun3();
Object.deliverChangeRecords(observer)");
+ }
+ CHECK_EQ(1, CompileRun("calls")->Int32Value());
+ CHECK_EQ(3, CompileRun("count")->Int32Value());
+}
+
+TEST(EndOfMicrotaskDelivery) {
+ HarmonyIsolate isolate;
+ HandleScope scope;
+ LocalContext context;
+ CompileRun(
+ "var obj = {};"
+ "var count = 0;"
+ "var observer = function(records) { count = records.length };"
+ "Object.observe(obj, observer);"
+ "obj.foo = 'bar';");
+ CHECK_EQ(1, CompileRun("count")->Int32Value());
+}
+
+TEST(DeliveryOrdering) {
+ HarmonyIsolate isolate;
+ HandleScope scope;
+ LocalContext context;
+ CompileRun(
+ "var obj1 = {};"
+ "var obj2 = {};"
+ "var ordering = [];"
+ "function observer2() { ordering.push(2); };"
+ "function observer1() { ordering.push(1); };"
+ "function observer3() { ordering.push(3); };"
+ "Object.observe(obj1, observer1);"
+ "Object.observe(obj1, observer2);"
+ "Object.observe(obj1, observer3);"
+ "obj1.foo = 'bar';");
+ CHECK_EQ(3, CompileRun("ordering.length")->Int32Value());
+ CHECK_EQ(1, CompileRun("ordering[0]")->Int32Value());
+ CHECK_EQ(2, CompileRun("ordering[1]")->Int32Value());
+ CHECK_EQ(3, CompileRun("ordering[2]")->Int32Value());
+ CompileRun(
+ "ordering = [];"
+ "Object.observe(obj2, observer3);"
+ "Object.observe(obj2, observer2);"
+ "Object.observe(obj2, observer1);"
+ "obj2.foo = 'baz'");
+ CHECK_EQ(3, CompileRun("ordering.length")->Int32Value());
+ CHECK_EQ(1, CompileRun("ordering[0]")->Int32Value());
+ CHECK_EQ(2, CompileRun("ordering[1]")->Int32Value());
+ CHECK_EQ(3, CompileRun("ordering[2]")->Int32Value());
+}
+
+TEST(DeliveryOrderingReentrant) {
+ HarmonyIsolate isolate;
+ HandleScope scope;
+ LocalContext context;
+ CompileRun(
+ "var obj = {};"
+ "var reentered = false;"
+ "var ordering = [];"
+ "function observer1() { ordering.push(1); };"
+ "function observer2() {"
+ " if (!reentered) {"
+ " obj.foo = 'baz';"
+ " reentered = true;"
+ " }"
+ " ordering.push(2);"
+ "};"
+ "function observer3() { ordering.push(3); };"
+ "Object.observe(obj, observer1);"
+ "Object.observe(obj, observer2);"
+ "Object.observe(obj, observer3);"
+ "obj.foo = 'bar';");
+ CHECK_EQ(5, CompileRun("ordering.length")->Int32Value());
+ CHECK_EQ(1, CompileRun("ordering[0]")->Int32Value());
+ CHECK_EQ(2, CompileRun("ordering[1]")->Int32Value());
+ CHECK_EQ(3, CompileRun("ordering[2]")->Int32Value());
+ // Note that we re-deliver to observers 1 and 2, while observer3
+ // already received the second record during the first round.
+ CHECK_EQ(1, CompileRun("ordering[3]")->Int32Value());
+ CHECK_EQ(2, CompileRun("ordering[1]")->Int32Value());
+}
+
+TEST(ObjectHashTableGrowth) {
+ HarmonyIsolate isolate;
+ HandleScope scope;
+ // Initializing this context sets up initial hash tables.
+ LocalContext context;
+ Handle<Value> obj = CompileRun("obj = {};");
+ Handle<Value> observer = CompileRun(
+ "var ran = false;"
+ "(function() { ran = true })");
+ {
+ // As does initializing this context.
+ LocalContext context2;
+ context2->Global()->Set(String::New("obj"), obj);
+ context2->Global()->Set(String::New("observer"), observer);
+ CompileRun(
+ "var objArr = [];"
+ // 100 objects should be enough to make the hash table grow
+ // (and thus relocate).
+ "for (var i = 0; i < 100; ++i) {"
+ " objArr.push({});"
+ " Object.observe(objArr[objArr.length-1], function(){});"
+ "}"
+ "Object.observe(obj, observer);");
+ }
+ // obj is now marked "is_observed", but our map has moved.
+ CompileRun("obj.foo = 'bar'");
+ CHECK(CompileRun("ran")->BooleanValue());
+}
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/error-accessors.js Mon Nov 12 06:53:34 2012
@@ -0,0 +1,54 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test that the message property of error objects is a data property.
+
+var o;
+
+// message is constructed using the constructor.
+var error1 = new Error("custom message");
+o = {};
+o.__proto__ = error1;
+
+assertEquals("custom message",
+ Object.getOwnPropertyDescriptor(error1, "message").value);
+o.message = "another message";
+assertEquals("another message", o.message);
+assertEquals("custom message", error1.message);
+
+// message is constructed by the runtime.
+var error2;
+try { x.x } catch (e) { error2 = e; }
+o = {};
+o.__proto__ = error2;
+
+assertEquals("x is not defined",
+ Object.getOwnPropertyDescriptor(error2, "message").value);
+o.message = "another message";
+assertEquals("another message", o.message);
+assertEquals("x is not defined", error2.message);
+
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/regress/regress-2398.js Mon Nov 12 06:53:34 2012
@@ -0,0 +1,41 @@
+// Copyright 2012 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.
+
+"use strict";
+
+var observed = false;
+
+var object = { get toString() { observed = true; } };
+Object.defineProperty(object, "ro", { value: 1 });
+
+try {
+
object.ro = 2; // TypeError caused by trying to write to read-only.
+} catch (e) {
+ e.message; // Forces formatting of the message object.
+}
+
+assertFalse(observed);
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/regress/regress-crbug-157019.js Mon Nov 12 06:53:34
2012
@@ -0,0 +1,54 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --nocrankshaft
+
+function makeConstructor() {
+ return function() {
+ this.a = 1;
+ this.b = 2;
+ };
+}
+
+var c1 = makeConstructor();
+var o1 = new c1();
+
+c1.prototype = {};
+
+for (var i = 0; i < 10; i++) {
+ var o = new c1();
+ for (var j = 0; j < 8; j++) {
+ o["x" + j] = 0;
+ }
+}
+
+var c2 = makeConstructor();
+var o2 = new c2();
+
+for (var i = 0; i < 50000; i++) {
+ new c2();
+}
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/regress/regress-crbug-160010.js Mon Nov 12 06:53:34
2012
@@ -0,0 +1,33 @@
+// Copyright 2012 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 str = "a";
+for (var i = 0; i < 28; i++) {
+ str += str;
+}
+JSON.stringify(str);
+
=======================================
--- /trunk/.gitignore Mon Oct 22 06:09:53 2012
+++ /trunk/.gitignore Mon Nov 12 06:53:34 2012
@@ -50,3 +50,7 @@
/xcodebuild
TAGS
*.Makefile
+GTAGS
+GRTAGS
+GSYMS
+GPATH
=======================================
--- /trunk/ChangeLog Tue Nov 6 04:13:00 2012
+++ /trunk/ChangeLog Mon Nov 12 06:53:34 2012
@@ -1,3 +1,29 @@
+2012-11-12: Version 3.15.2
+
+ Function::GetScriptOrigin supplies sourceURL when script name is
+ not available. (Chromium issue 159413)
+
+ Made formatting error message side-effect-free. (issue 2398)
+
+ Fixed length check in JSON.stringify. (Chromium issue 160010)
+
+ ES6: Added support for Set and Map clear method (issue 2400)
+
+ Fixed slack tracking when instance prototype changes.
+ (Chromium issue 157019)
+
+ Fixed disabling of code flusher while marking. (Chromium issue
159140)
+
+ Added a test case for object grouping in a scavenger GC (issue
2077)
+
+ Support shared library build of Android for v8.
+ (Chromium issue 158821)
+
+ ES6: Added support for size to Set and Map (issue 2395)
+
+ Performance and stability improvements on all platforms.
+
+
2012-11-06: Version 3.15.1
Put incremental code flushing behind a flag. (Chromium issue
159140)
=======================================
--- /trunk/include/v8.h Wed Nov 7 01:25:55 2012
+++ /trunk/include/v8.h Mon Nov 12 06:53:34 2012
@@ -402,6 +402,18 @@
* or followed by a global GC epilogue callback.
*/
inline void MarkIndependent();
+ inline void MarkIndependent(Isolate* isolate);
+
+ /**
+ * Marks the reference to this object partially dependent. Partially
+ * dependent handles only depend on other partially dependent handles and
+ * these dependencies are provided through object groups. It provides a
way
+ * to build smaller object groups for young objects that represent only a
+ * subset of all external dependencies. This mark is automatically
cleared
+ * after each garbage collection.
+ */
+ inline void MarkPartiallyDependent();
+ inline void MarkPartiallyDependent(Isolate* isolate);
/** Returns true if this handle was previously marked as independent. */
inline bool IsIndependent() const;
@@ -3256,7 +3268,10 @@
* After each garbage collection, object groups are removed. It is
* intended to be used in the before-garbage-collection callback
* function, for instance to simulate DOM tree connections among JS
- * wrapper objects.
+ * wrapper objects. Object groups for all dependent handles need to
+ * be provided for kGCTypeMarkSweepCompact collections, for all other
+ * garbage collection types it is sufficient to provide object groups
+ * for partially dependent handles only.
* See v8-profiler.h for RetainedObjectInfo interface description.
*/
static void AddObjectGroup(Persistent<Value>* objects,
@@ -3497,6 +3512,11 @@
WeakReferenceCallback);
static void ClearWeak(internal::Object** global_handle);
static void MarkIndependent(internal::Object** global_handle);
+ static void MarkIndependent(internal::Isolate* isolate,
+ internal::Object** global_handle);
+ static void MarkPartiallyDependent(internal::Object** global_handle);
+ static void MarkPartiallyDependent(internal::Isolate* isolate,
+ internal::Object** global_handle);
static bool IsGlobalIndependent(internal::Object** global_handle);
static bool IsGlobalIndependent(internal::Isolate* isolate,
internal::Object** global_handle);
@@ -4102,7 +4122,7 @@
static const int kNullValueRootIndex = 7;
static const int kTrueValueRootIndex = 8;
static const int kFalseValueRootIndex = 9;
- static const int kEmptySymbolRootIndex = 117;
+ static const int kEmptySymbolRootIndex = 118;
static const int kJSObjectType = 0xaa;
static const int kFirstNonstringType = 0x80;
@@ -4284,6 +4304,23 @@
void Persistent<T>::MarkIndependent() {
V8::MarkIndependent(reinterpret_cast<internal::Object**>(**this));
}
+
+template <class T>
+void Persistent<T>::MarkIndependent(Isolate* isolate) {
+ V8::MarkIndependent(reinterpret_cast<internal::Isolate*>(isolate),
+ reinterpret_cast<internal::Object**>(**this));
+}
+
+template <class T>
+void Persistent<T>::MarkPartiallyDependent() {
+ V8::MarkPartiallyDependent(reinterpret_cast<internal::Object**>(**this));
+}
+
+template <class T>
+void Persistent<T>::MarkPartiallyDependent(Isolate* isolate) {
+ V8::MarkPartiallyDependent(reinterpret_cast<internal::Isolate*>(isolate),
+ reinterpret_cast<internal::Object**>(**this));
+}
template <class T>
void Persistent<T>::SetWrapperClassId(uint16_t class_id) {
=======================================
--- /trunk/src/accessors.cc Wed Oct 10 10:07:22 2012
+++ /trunk/src/accessors.cc Mon Nov 12 06:53:34 2012
@@ -93,6 +93,47 @@
if (wrapper->map() == number_map) return wrapper->value();
return value;
}
+
+
+static MaybeObject* ArraySetLengthObserved(Isolate* isolate,
+ Handle<JSArray> array,
+ Handle<Object>
new_length_handle) {
+ List<Handle<String> > indices;
+ List<Handle<Object> > old_values;
+ Handle<Object> old_length_handle(array->length(), isolate);
+ uint32_t old_length = 0;
+ CHECK(old_length_handle->ToArrayIndex(&old_length));
+ uint32_t new_length = 0;
+ CHECK(new_length_handle->ToArrayIndex(&new_length));
+ // TODO(adamk): This loop can be very slow for arrays in dictionary mode.
+ // Find another way to iterate over arrays with dictionary elements.
+ for (uint32_t i = old_length - 1; i + 1 > new_length; --i) {
+ PropertyAttributes attributes = array->GetLocalElementAttribute(i);
+ if (attributes == ABSENT) continue;
+ // A non-configurable property will cause the truncation operation to
+ // stop at this index.
+ if (attributes == DONT_DELETE) break;
+ // TODO(adamk): Don't fetch the old value if it's an accessor.
+ old_values.Add(Object::GetElement(array, i));
+ indices.Add(isolate->factory()->Uint32ToString(i));
+ }
+
+ MaybeObject* result = array->SetElementsLength(*new_length_handle);
+ Handle<Object> hresult;
+ if (!result->ToHandle(&hresult)) return result;
+
+ CHECK(array->length()->ToArrayIndex(&new_length));
+ if (old_length != new_length) {
+ for (int i = 0; i < indices.length(); ++i) {
+ JSObject::EnqueueChangeRecord(
+ array, "deleted", indices[i], old_values[i]);
+ }
+ JSObject::EnqueueChangeRecord(
+ array, "updated", isolate->factory()->length_symbol(),
+ old_length_handle);
+ }
+ return *hresult;
+}
MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value,
void*) {
@@ -112,7 +153,7 @@
HandleScope scope(isolate);
// Protect raw pointers.
- Handle<JSObject> object_handle(object, isolate);
+ Handle<JSArray> array_handle(JSArray::cast(object), isolate);
Handle<Object> value_handle(value, isolate);
bool has_exception;
@@ -122,7 +163,11 @@
if (has_exception) return Failure::Exception();
if (uint32_v->Number() == number_v->Number()) {
- return
Handle<JSArray>::cast(object_handle)->SetElementsLength(*uint32_v);
+ if (FLAG_harmony_observation && array_handle->map()->is_observed()) {
+ return ArraySetLengthObserved(isolate, array_handle, uint32_v);
+ } else {
+ return array_handle->SetElementsLength(*uint32_v);
+ }
}
return isolate->Throw(
*isolate->factory()->NewRangeError("invalid_array_length",
=======================================
--- /trunk/src/api.cc Wed Nov 7 01:25:55 2012
+++ /trunk/src/api.cc Mon Nov 12 06:53:34 2012
@@ -646,6 +646,27 @@
LOG_API(isolate, "MarkIndependent");
isolate->global_handles()->MarkIndependent(object);
}
+
+
+void V8::MarkIndependent(i::Isolate* isolate, i::Object** object) {
+ ASSERT(isolate == i::Isolate::Current());
+ LOG_API(isolate, "MarkIndependent");
+ isolate->global_handles()->MarkIndependent(object);
+}
+
+
+void V8::MarkPartiallyDependent(i::Object** object) {
+ i::Isolate* isolate = i::Isolate::Current();
+ LOG_API(isolate, "MarkPartiallyDependent");
+ isolate->global_handles()->MarkPartiallyDependent(object);
+}
+
+
+void V8::MarkPartiallyDependent(i::Isolate* isolate, i::Object** object) {
+ ASSERT(isolate == i::Isolate::Current());
+ LOG_API(isolate, "MarkPartiallyDependent");
+ isolate->global_handles()->MarkPartiallyDependent(object);
+}
bool V8::IsGlobalIndependent(i::Object** obj) {
@@ -3714,8 +3735,9 @@
i::Handle<i::JSFunction> func = Utils::OpenHandle(this);
if (func->shared()->script()->IsScript()) {
i::Handle<i::Script> script(i::Script::cast(func->shared()->script()));
+ i::Handle<i::Object> scriptName = GetScriptNameOrSourceURL(script);
v8::ScriptOrigin origin(
- Utils::ToLocal(i::Handle<i::Object>(script->name())),
+ Utils::ToLocal(scriptName),
v8::Integer::New(script->line_offset()->value()),
v8::Integer::New(script->column_offset()->value()));
return origin;
@@ -6512,6 +6534,7 @@
void Testing::DeoptimizeAll() {
+ i::HandleScope scope;
internal::Deoptimizer::DeoptimizeAll();
}
=======================================
--- /trunk/src/arm/assembler-arm-inl.h Wed Oct 31 03:02:10 2012
+++ /trunk/src/arm/assembler-arm-inl.h Mon Nov 12 06:53:34 2012
@@ -163,6 +163,24 @@
host(), NULL, cell);
}
}
+
+
+static const int kNoCodeAgeSequenceLength = 3;
+
+Code* RelocInfo::code_age_stub() {
+ ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
+ return Code::GetCodeFromTargetAddress(
+ Memory::Address_at(pc_ + Assembler::kInstrSize *
+ (kNoCodeAgeSequenceLength - 1)));
+}
+
+
+void RelocInfo::set_code_age_stub(Code* stub) {
+ ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
+ Memory::Address_at(pc_ + Assembler::kInstrSize *
+ (kNoCodeAgeSequenceLength - 1)) =
+ stub->instruction_start();
+}
Address RelocInfo::call_address() {
@@ -238,6 +256,8 @@
visitor->VisitGlobalPropertyCell(this);
} else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
visitor->VisitExternalReference(this);
+ } else if (RelocInfo::IsCodeAgeSequence(mode)) {
+ visitor->VisitCodeAgeSequence(this);
#ifdef ENABLE_DEBUGGER_SUPPORT
// TODO(isolates): Get a cached isolate below.
} else if (((RelocInfo::IsJSReturn(mode) &&
@@ -264,6 +284,8 @@
StaticVisitor::VisitGlobalPropertyCell(heap, this);
} else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
StaticVisitor::VisitExternalReference(this);
+ } else if (RelocInfo::IsCodeAgeSequence(mode)) {
+ StaticVisitor::VisitCodeAgeSequence(heap, this);
#ifdef ENABLE_DEBUGGER_SUPPORT
} else if (heap->isolate()->debug()->has_break_points() &&
((RelocInfo::IsJSReturn(mode) &&
=======================================
--- /trunk/src/arm/assembler-arm.cc Wed Oct 31 03:02:10 2012
+++ /trunk/src/arm/assembler-arm.cc Mon Nov 12 06:53:34 2012
@@ -325,9 +325,7 @@
Assembler::Assembler(Isolate* arg_isolate, void* buffer, int buffer_size)
: AssemblerBase(arg_isolate),
recorded_ast_id_(TypeFeedbackId::None()),
- positions_recorder_(this),
- emit_debug_code_(FLAG_debug_code),
- predictable_code_size_(false) {
+ positions_recorder_(this) {
if (buffer == NULL) {
// Do our own buffer management.
if (buffer_size <= kMinimalBufferSize) {
=======================================
--- /trunk/src/arm/assembler-arm.h Wed Oct 31 03:02:10 2012
+++ /trunk/src/arm/assembler-arm.h Mon Nov 12 06:53:34 2012
@@ -648,14 +648,6 @@
// upon destruction of the assembler.
Assembler(Isolate* isolate, void* buffer, int buffer_size);
~Assembler();
-
- // Overrides the default provided by FLAG_debug_code.
- void set_emit_debug_code(bool value) { emit_debug_code_ = value; }
-
- // Avoids using instructions that vary in size in unpredictable ways
between
- // the snapshot and the running VM. This is needed by the full compiler
so
- // that it can recompile code with debug support and fix the PC.
- void set_predictable_code_size(bool value) { predictable_code_size_ =
value; }
// GetCode emits any pending (non-emitted) code and fills the descriptor
// desc. GetCode() is idempotent; it returns the same result if no other
@@ -1184,8 +1176,6 @@
// Jump unconditionally to given label.
void jmp(Label* L) { b(L, al); }
-
- bool predictable_code_size() const { return predictable_code_size_; }
static bool use_immediate_embedded_pointer_loads(
const Assembler* assembler) {
@@ -1344,8 +1334,6 @@
// member variable is a way to pass the information from the call site to
// the relocation info.
TypeFeedbackId recorded_ast_id_;
-
- bool emit_debug_code() const { return emit_debug_code_; }
int buffer_space() const { return reloc_info_writer.pos() - pc_; }
@@ -1497,10 +1485,6 @@
friend class BlockConstPoolScope;
PositionsRecorder positions_recorder_;
-
- bool emit_debug_code_;
- bool predictable_code_size_;
-
friend class PositionsRecorder;
friend class EnsureSpace;
};
@@ -1514,26 +1498,6 @@
};
-class PredictableCodeSizeScope {
- public:
- explicit PredictableCodeSizeScope(Assembler* assembler)
- : asm_(assembler) {
- old_value_ = assembler->predictable_code_size();
- assembler->set_predictable_code_size(true);
- }
-
- ~PredictableCodeSizeScope() {
- if (!old_value_) {
- asm_->set_predictable_code_size(false);
- }
- }
-
- private:
- Assembler* asm_;
- bool old_value_;
-};
-
-
} } // namespace v8::internal
#endif // V8_ARM_ASSEMBLER_ARM_H_
=======================================
--- /trunk/src/arm/builtins-arm.cc Tue Aug 28 02:06:19 2012
+++ /trunk/src/arm/builtins-arm.cc Mon Nov 12 06:53:34 2012
@@ -1226,6 +1226,39 @@
}
+static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
+ // For now, we are relying on the fact that make_code_young doesn't do
any
+ // garbage collection which allows us to save/restore the registers
without
+ // worrying about which of them contain pointers. We also don't build an
+ // internal frame to make the code faster, since we shouldn't have to do
stack
+ // crawls in MakeCodeYoung. This seems a bit fragile.
+
+ // The following registers must be saved and restored when calling
through to
+ // the runtime:
+ // r0 - contains return address (beginning of patch sequence)
+ // r1 - function object
+ FrameScope scope(masm, StackFrame::MANUAL);
+ __ stm(db_w, sp, r0.bit() | r1.bit() | fp.bit() | lr.bit());
+ __ PrepareCallCFunction(1, 0, r1);
+ __ CallCFunction(
+ ExternalReference::get_make_code_young_function(masm->isolate()), 1);
+ __ ldm(ia_w, sp, r0.bit() | r1.bit() | fp.bit() | lr.bit());
+ __ mov(pc, r0);
+}
+
+#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \
+void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \
+ MacroAssembler* masm) { \
+ GenerateMakeCodeYoungAgainCommon(masm); \
+} \
+void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \
+ MacroAssembler* masm) { \
+ GenerateMakeCodeYoungAgainCommon(masm); \
+}
+CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
+#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
+
+
static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
Deoptimizer::BailoutType
type) {
{
=======================================
--- /trunk/src/arm/code-stubs-arm.cc Mon Oct 22 06:09:53 2012
+++ /trunk/src/arm/code-stubs-arm.cc Mon Nov 12 06:53:34 2012
@@ -4923,7 +4923,7 @@
// subject: Subject string
// regexp_data: RegExp data (FixedArray)
// r0: Instance type of subject string
- STATIC_ASSERT(4 == kAsciiStringTag);
+ STATIC_ASSERT(4 == kOneByteStringTag);
STATIC_ASSERT(kTwoByteStringTag == 0);
// Find the code object based on the assumptions above.
__ and_(r0, r0, Operand(kStringEncodingMask));
@@ -5999,23 +5999,28 @@
STATIC_ASSERT(kSmiTag == 0);
STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
- // I.e., arithmetic shift right by one un-smi-tags.
- __ mov(r2, Operand(r2, ASR, 1), SetCC);
- __ mov(r3, Operand(r3, ASR, 1), SetCC, cc);
- // If either to or from had the smi tag bit set, then carry is set now.
- __ b(cs, &runtime); // Either "from" or "to" is not a smi.
+ // Arithmetic shift right by one un-smi-tags. In this case we rotate
right
+ // instead because we bail out on non-smi values: ROR and ASR are
equivalent
+ // for smis but they set the flags in a way that's easier to optimize.
+ __ mov(r2, Operand(r2, ROR, 1), SetCC);
+ __ mov(r3, Operand(r3, ROR, 1), SetCC, cc);
+ // If either to or from had the smi tag bit set, then C is set now, and N
+ // has the same value: we rotated by 1, so the bottom bit is now the top
bit.
// We want to bailout to runtime here if From is negative. In that
case, the
// next instruction is not executed and we fall through to bailing out to
- // runtime. pl is the opposite of mi.
- // Both r2 and r3 are untagged integers.
- __ sub(r2, r2, Operand(r3), SetCC, pl);
- __ b(mi, &runtime); // Fail if from > to.
+ // runtime.
+ // Executed if both r2 and r3 are untagged integers.
+ __ sub(r2, r2, Operand(r3), SetCC, cc);
+ // One of the above un-smis or the above SUB could have set N==1.
+ __ b(mi, &runtime); // Either "from" or "to" is not an smi, or from >
to.
// Make sure first argument is a string.
__ ldr(r0, MemOperand(sp, kStringOffset));
STATIC_ASSERT(kSmiTag == 0);
- __ JumpIfSmi(r0, &runtime);
- Condition is_string = masm->IsObjectStringType(r0, r1);
+ // Do a JumpIfSmi, but fold its jump into the subsequent string test.
+ __ tst(r0, Operand(kSmiTagMask));
+ Condition is_string = masm->IsObjectStringType(r0, r1, ne);
+ ASSERT(is_string == eq);
__ b(NegateCondition(is_string), &runtime);
// Short-cut for the case of trivial substring.
@@ -6086,7 +6091,7 @@
// string's encoding is wrong because we always have to recheck
encoding of
// the newly created string's parent anyways due to externalized
strings.
Label two_byte_slice, set_slice_header;
- STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
+ STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0);
STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
__ tst(r1, Operand(kStringEncodingMask));
__ b(eq, &two_byte_slice);
@@ -6129,7 +6134,7 @@
__ bind(&allocate_result);
// Sequential acii string. Allocate the result.
- STATIC_ASSERT((kAsciiStringTag & kStringEncodingMask) != 0);
+ STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0);
__ tst(r1, Operand(kStringEncodingMask));
__ b(eq, &two_byte_sequential);
@@ -6494,9 +6499,9 @@
__ tst(r5, Operand(kAsciiDataHintMask), ne);
__ b(ne, &ascii_data);
__ eor(r4, r4, Operand(r5));
- STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0);
- __ and_(r4, r4, Operand(kAsciiStringTag | kAsciiDataHintTag));
- __ cmp(r4, Operand(kAsciiStringTag | kAsciiDataHintTag));
+ STATIC_ASSERT(kOneByteStringTag != 0 && kAsciiDataHintTag != 0);
+ __ and_(r4, r4, Operand(kOneByteStringTag | kAsciiDataHintTag));
+ __ cmp(r4, Operand(kOneByteStringTag | kAsciiDataHintTag));
__ b(eq, &ascii_data);
// Allocate a two byte cons string.
=======================================
--- /trunk/src/arm/codegen-arm.cc Fri Jul 27 01:03:27 2012
+++ /trunk/src/arm/codegen-arm.cc Mon Nov 12 06:53:34 2012
@@ -452,6 +452,92 @@
#undef __
+// add(r0, pc, Operand(-8))
+static const uint32_t kCodeAgePatchFirstInstruction = 0xe24f0008;
+
+static byte* GetNoCodeAgeSequence(uint32_t* length) {
+ // The sequence of instructions that is patched out for aging code is the
+ // following boilerplate stack-building prologue that is found in
FUNCTIONS
+ static bool initialized = false;
+ static uint32_t sequence[kNoCodeAgeSequenceLength];
+ byte* byte_sequence = reinterpret_cast<byte*>(sequence);
+ *length = kNoCodeAgeSequenceLength * Assembler::kInstrSize;
+ if (!initialized) {
+ CodePatcher patcher(byte_sequence, kNoCodeAgeSequenceLength);
+ patcher.masm()->stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() |
lr.bit());
+ patcher.masm()->LoadRoot(ip, Heap::kUndefinedValueRootIndex);
+ patcher.masm()->add(fp, sp, Operand(2 * kPointerSize));
+ initialized = true;
+ }
+ return byte_sequence;
+}
+
+
+byte* Code::FindPlatformCodeAgeSequence() {
+ byte* start = instruction_start();
+ uint32_t young_length;
+ byte* young_sequence = GetNoCodeAgeSequence(&young_length);
+ if (!memcmp(start, young_sequence, young_length) ||
+ Memory::uint32_at(start) == kCodeAgePatchFirstInstruction) {
+ return start;
+ } else {
+ byte* start_after_strict = NULL;
+ if (kind() == FUNCTION) {
+ start_after_strict = start + kSizeOfFullCodegenStrictModePrologue;
+ } else {
+ ASSERT(kind() == OPTIMIZED_FUNCTION);
+ start_after_strict = start + kSizeOfOptimizedStrictModePrologue;
+ }
+ ASSERT(!memcmp(start_after_strict, young_sequence, young_length) ||
+ Memory::uint32_at(start_after_strict) ==
+ kCodeAgePatchFirstInstruction);
+ return start_after_strict;
+ }
+}
+
+
+bool Code::IsYoungSequence(byte* sequence) {
+ uint32_t young_length;
+ byte* young_sequence = GetNoCodeAgeSequence(&young_length);
+ bool result = !memcmp(sequence, young_sequence, young_length);
+ ASSERT(result ||
+ Memory::uint32_at(sequence) == kCodeAgePatchFirstInstruction);
+ return result;
+}
+
+
+void Code::GetCodeAgeAndParity(byte* sequence, Age* age,
+ MarkingParity* parity) {
+ if (IsYoungSequence(sequence)) {
+ *age = kNoAge;
+ *parity = NO_MARKING_PARITY;
+ } else {
+ Address target_address = Memory::Address_at(
+ sequence + Assembler::kInstrSize * (kNoCodeAgeSequenceLength - 1));
+ Code* stub = GetCodeFromTargetAddress(target_address);
+ GetCodeAgeAndParity(stub, age, parity);
+ }
+}
+
+
+void Code::PatchPlatformCodeAge(byte* sequence,
+ Code::Age age,
+ MarkingParity parity) {
+ uint32_t young_length;
+ byte* young_sequence = GetNoCodeAgeSequence(&young_length);
+ if (age == kNoAge) {
+ memcpy(sequence, young_sequence, young_length);
+ CPU::FlushICache(sequence, young_length);
+ } else {
+ Code* stub = GetCodeAgeStub(age, parity);
+ CodePatcher patcher(sequence, young_length / Assembler::kInstrSize);
+ patcher.masm()->add(r0, pc, Operand(-8));
+ patcher.masm()->ldr(pc, MemOperand(pc, -4));
+
patcher.masm()->dd(reinterpret_cast<uint32_t>(stub->instruction_start()));
+ }
+}
+
+
} } // namespace v8::internal
#endif // V8_TARGET_ARCH_ARM
=======================================
--- /trunk/src/arm/codegen-arm.h Tue Nov 29 06:28:56 2011
+++ /trunk/src/arm/codegen-arm.h Mon Nov 12 06:53:34 2012
@@ -34,6 +34,9 @@
namespace v8 {
namespace internal {
+static const int kSizeOfFullCodegenStrictModePrologue = 16;
+static const int kSizeOfOptimizedStrictModePrologue = 16;
+
// Forward declarations
class CompilationInfo;
=======================================
--- /trunk/src/arm/full-codegen-arm.cc Mon Oct 22 06:09:53 2012
+++ /trunk/src/arm/full-codegen-arm.cc Mon Nov 12 06:53:34 2012
@@ -149,12 +149,15 @@
// function calls.
if (!info->is_classic_mode() || info->is_native()) {
Label ok;
+ Label begin;
+ __ bind(&begin);
__ cmp(r5, Operand(0));
__ b(eq, &ok);
int receiver_offset = info->scope()->num_parameters() * kPointerSize;
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
__ str(r2, MemOperand(sp, receiver_offset));
__ bind(&ok);
+ ASSERT_EQ(kSizeOfFullCodegenStrictModePrologue, ok.pos() -
begin.pos());
}
// Open a frame scope to indicate that there is a frame on the stack.
The
@@ -164,12 +167,12 @@
int locals_count = info->scope()->num_stack_slots();
- __ Push(lr, fp, cp, r1);
- if (locals_count > 0) {
- // Load undefined value here, so the value is ready for the loop
- // below.
- __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
- }
+ // The following four instructions must remain together and unmodified
for
+ // code aging to work properly.
+ __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
+ // Load undefined value here, so the value is ready for the loop
+ // below.
+ __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
// Adjust fp to point to caller's fp.
__ add(fp, sp, Operand(2 * kPointerSize));
=======================================
--- /trunk/src/arm/lithium-arm.cc Tue Nov 6 04:13:00 2012
+++ /trunk/src/arm/lithium-arm.cc Mon Nov 12 06:53:34 2012
@@ -1881,6 +1881,7 @@
(instr->representation().IsDouble() &&
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
+
LOperand* external_pointer = UseRegister(instr->elements());
result = new(zone()) LLoadKeyed(external_pointer, key);
}
@@ -1905,32 +1906,22 @@
LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
- ElementsKind elements_kind = instr->elements_kind();
- bool needs_write_barrier = instr->NeedsWriteBarrier();
- LOperand* key = needs_write_barrier
- ? UseTempRegister(instr->key())
- : UseRegisterOrConstantAtStart(instr->key());
- bool val_is_temp_register =
- elements_kind == EXTERNAL_PIXEL_ELEMENTS ||
- elements_kind == EXTERNAL_FLOAT_ELEMENTS;
- LOperand* val = val_is_temp_register || needs_write_barrier
- ? UseTempRegister(instr->value())
- : UseRegister(instr->value());
+ LOperand* elements = UseRegisterAtStart(instr->elements());
+ LOperand* key;
+ LOperand* val;
+ if (instr->NeedsWriteBarrier()) {
+ key = UseTempRegister(instr->key());
+ val = UseTempRegister(instr->value());
+ } else {
+ key = UseRegisterOrConstantAtStart(instr->key());
+ val = UseRegisterAtStart(instr->value());
+ }
- LStoreKeyed* result = NULL;
+#ifdef DEBUG
if (!instr->is_external()) {
ASSERT(instr->elements()->representation().IsTagged());
-
- LOperand* object = NULL;
- if (instr->value()->representation().IsDouble()) {
- object = UseRegisterAtStart(instr->elements());
- } else {
- ASSERT(instr->value()->representation().IsTagged());
- object = UseTempRegister(instr->elements());
- }
-
- result = new(zone()) LStoreKeyed(object, key, val);
} else {
+ ElementsKind elements_kind = instr->elements_kind();
ASSERT(
(instr->value()->representation().IsInteger32() &&
(elements_kind != EXTERNAL_FLOAT_ELEMENTS) &&
@@ -1939,11 +1930,10 @@
((elements_kind == EXTERNAL_FLOAT_ELEMENTS) ||
(elements_kind == EXTERNAL_DOUBLE_ELEMENTS))));
ASSERT(instr->elements()->representation().IsExternal());
-
- LOperand* external_pointer = UseRegister(instr->elements());
- result = new(zone()) LStoreKeyed(external_pointer, key, val);
}
+#endif
+ LStoreKeyed* result = new(zone()) LStoreKeyed(elements, key, val);
ASSERT(result != NULL);
return result;
}
=======================================
--- /trunk/src/arm/lithium-codegen-arm.cc Tue Nov 6 04:13:00 2012
+++ /trunk/src/arm/lithium-codegen-arm.cc Mon Nov 12 06:53:34 2012
@@ -138,15 +138,23 @@
// function calls.
if (!info_->is_classic_mode() || info_->is_native()) {
Label ok;
+ Label begin;
+ __ bind(&begin);
__ cmp(r5, Operand(0));
__ b(eq, &ok);
int receiver_offset = scope()->num_parameters() * kPointerSize;
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
__ str(r2, MemOperand(sp, receiver_offset));
__ bind(&ok);
+ ASSERT_EQ(kSizeOfOptimizedStrictModePrologue, ok.pos() - begin.pos());
}
+ // The following three instructions must remain together and unmodified
for
+ // code aging to work properly.
__ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
+ // Add unused load of ip to ensure prologue sequence is identical for
+ // full-codegen and lithium-codegen.
+ __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
__ add(fp, sp, Operand(2 * kPointerSize)); // Adjust FP to point to
saved FP.
// Reserve space for the stack slots needed by the code.
@@ -3040,13 +3048,12 @@
(instr->additional_index() << element_size_shift)));
}
+ __ vldr(result, elements, 0);
if (instr->hydrogen()->RequiresHoleCheck()) {
__ ldr(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
__ cmp(scratch, Operand(kHoleNanUpper32));
DeoptimizeIf(eq, instr->environment());
}
-
- __ vldr(result, elements, 0);
}
=======================================
--- /trunk/src/arm/macro-assembler-arm.cc Mon Oct 22 06:09:53 2012
+++ /trunk/src/arm/macro-assembler-arm.cc Mon Nov 12 06:53:34 2012
@@ -422,6 +422,16 @@
void MacroAssembler::LoadRoot(Register destination,
Heap::RootListIndex index,
Condition cond) {
+ if (CpuFeatures::IsSupported(MOVW_MOVT_IMMEDIATE_LOADS) &&
+ !Heap::RootCanBeWrittenAfterInitialization(index)) {
+ Handle<Object> root(isolate()->heap()->roots_array_start()[index]);
+ if (!isolate()->heap()->InNewSpace(*root)) {
+ // The CPU supports fast immediate values, and this root will never
+ // change. We will load it as a relocatable immediate value.
+ mov(destination, Operand(root), LeaveCC, cond);
+ return;
+ }
+ }
ldr(destination, MemOperand(kRootRegister, index << kPointerSizeLog2),
cond);
}
@@ -3684,7 +3694,7 @@
// For ASCII (char-size of 1) we shift the smi tag away to get the
length.
// For UC16 (char-size of 2) we just leave the smi tag in place, thereby
// getting the length multiplied by 2.
- ASSERT(kAsciiStringTag == 4 && kStringEncodingMask == 4);
+ ASSERT(kOneByteStringTag == 4 && kStringEncodingMask == 4);
ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
ldr(ip, FieldMemOperand(value, String::kLengthOffset));
tst(instance_type, Operand(kStringEncodingMask));
=======================================
--- /trunk/src/arm/macro-assembler-arm.h Mon Oct 22 06:09:53 2012
+++ /trunk/src/arm/macro-assembler-arm.h Mon Nov 12 06:53:34 2012
@@ -893,12 +893,15 @@
// Load and check the instance type of an object for being a string.
// Loads the type into the second argument register.
- // Returns a condition that will be enabled if the object was a string.
+ // Returns a condition that will be enabled if the object was a string
+ // and the passed-in condition passed. If the passed-in condition failed
+ // then flags remain unchanged.
Condition IsObjectStringType(Register obj,
- Register type) {
- ldr(type, FieldMemOperand(obj, HeapObject::kMapOffset));
- ldrb(type, FieldMemOperand(type, Map::kInstanceTypeOffset));
- tst(type, Operand(kIsNotStringMask));
+ Register type,
+ Condition cond = al) {
+ ldr(type, FieldMemOperand(obj, HeapObject::kMapOffset), cond);
+ ldrb(type, FieldMemOperand(type, Map::kInstanceTypeOffset), cond);
+ tst(type, Operand(kIsNotStringMask), cond);
ASSERT_EQ(0, kStringTag);
return eq;
}
@@ -1202,7 +1205,7 @@
// Souce and destination can be the same register.
void UntagAndJumpIfNotSmi(Register dst, Register src, Label*
non_smi_case);
- // Jump the register contains a smi.
+ // Jump if the register contains a smi.
inline void JumpIfSmi(Register value, Label* smi_label) {
tst(value, Operand(kSmiTagMask));
b(eq, smi_label);
=======================================
--- /trunk/src/arm/simulator-arm.cc Tue Nov 6 04:13:00 2012
+++ /trunk/src/arm/simulator-arm.cc Mon Nov 12 06:53:34 2012
@@ -1387,7 +1387,14 @@
}
case ROR: {
- UNIMPLEMENTED();
+ if (shift_amount == 0) {
+ *carry_out = c_flag_;
+ } else {
+ uint32_t left = static_cast<uint32_t>(result) >> shift_amount;
+ uint32_t right = static_cast<uint32_t>(result) << (32 -
shift_amount);
+ result = right | left;
+ *carry_out = (static_cast<uint32_t>(result) >> 31) != 0;
+ }
break;
}
=======================================
--- /trunk/src/arm/stub-cache-arm.cc Mon Oct 15 04:51:39 2012
+++ /trunk/src/arm/stub-cache-arm.cc Mon Nov 12 06:53:34 2012
@@ -3467,7 +3467,13 @@
// r1: constructor function
// r2: initial map
// r7: undefined
+ ASSERT(function->has_initial_map());
__ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
+#ifdef DEBUG
+ int instance_size = function->initial_map()->instance_size();
+ __ cmp(r3, Operand(instance_size >> kPointerSizeLog2));
+ __ Check(eq, "Instance size of initial map changed.");
+#endif
__ AllocateInNewSpace(r3, r4, r5, r6, &generic_stub_call, SIZE_IN_WORDS);
// Allocated the JSObject, now initialize the fields. Map is set to
initial
@@ -3525,7 +3531,6 @@
}
// Fill the unused in-object property fields with undefined.
- ASSERT(function->has_initial_map());
for (int i = shared->this_property_assignments_count();
i < function->initial_map()->inobject_properties();
i++) {
=======================================
--- /trunk/src/array.js Wed Oct 31 03:02:10 2012
+++ /trunk/src/array.js Mon Nov 12 06:53:34 2012
@@ -441,8 +441,8 @@
}
n--;
var value = this[n];
+ delete this[n];
this.length = n;
- delete this[n];
return value;
}
@@ -581,7 +581,7 @@
var first = this[0];
- if (IS_ARRAY(this)) {
+ if (IS_ARRAY(this) && !%IsObserved(this)) {
SmartMove(this, 0, 1, len, 0);
} else {
SimpleMove(this, 0, 1, len, 0);
@@ -602,7 +602,7 @@
var len = TO_UINT32(this.length);
var num_arguments = %_ArgumentsLength();
- if (IS_ARRAY(this)) {
+ if (IS_ARRAY(this) && !%IsObserved(this)) {
SmartMove(this, 0, 0, len, num_arguments);
} else {
SimpleMove(this, 0, 0, len, num_arguments);
@@ -649,6 +649,7 @@
if (end_i < start_i) return result;
if (IS_ARRAY(this) &&
+ !%IsObserved(this) &&
(end_i > 1000) &&
(%EstimateNumberOfElements(this) < end_i)) {
SmartSlice(this, start_i, end_i - start_i, len, result);
@@ -705,7 +706,9 @@
var use_simple_splice = true;
- if (IS_ARRAY(this) && num_additional_args !== del_count) {
+ if (IS_ARRAY(this) &&
+ !%IsObserved(this) &&
+ num_additional_args !== del_count) {
// If we are only deleting/moving a few things near the end of the
// array then the simple version is going to be faster, because it
// doesn't touch most of the array.
=======================================
--- /trunk/src/assembler.cc Mon Oct 15 04:51:39 2012
+++ /trunk/src/assembler.cc Mon Nov 12 06:53:34 2012
@@ -108,7 +108,9 @@
AssemblerBase::AssemblerBase(Isolate* isolate)
: isolate_(isolate),
- jit_cookie_(0) {
+ jit_cookie_(0),
+ emit_debug_code_(FLAG_debug_code),
+ predictable_code_size_(false) {
if (FLAG_mask_constants_with_cookie && isolate != NULL) {
jit_cookie_ = V8::RandomPrivate(isolate);
}
@@ -313,6 +315,7 @@
#ifdef DEBUG
byte* begin_pos = pos_;
#endif
+ ASSERT(rinfo->rmode() < RelocInfo::NUMBER_OF_MODES);
ASSERT(rinfo->pc() - last_pc_ >= 0);
ASSERT(RelocInfo::LAST_STANDARD_NONCOMPACT_ENUM -
RelocInfo::LAST_COMPACT_ENUM
<= kMaxStandardNonCompactModes);
@@ -570,6 +573,15 @@
}
}
}
+ if (code_age_sequence_ != NULL) {
+ byte* old_code_age_sequence = code_age_sequence_;
+ code_age_sequence_ = NULL;
+ if (SetMode(RelocInfo::CODE_AGE_SEQUENCE)) {
+ rinfo_.data_ = 0;
+ rinfo_.pc_ = old_code_age_sequence;
+ return;
+ }
+ }
done_ = true;
}
@@ -585,6 +597,12 @@
mode_mask_ = mode_mask;
last_id_ = 0;
last_position_ = 0;
+ byte* sequence = code->FindCodeAgeSequence();
+ if (sequence != NULL && !Code::IsYoungSequence(sequence)) {
+ code_age_sequence_ = sequence;
+ } else {
+ code_age_sequence_ = NULL;
+ }
if (mode_mask_ == 0) pos_ = end_;
next();
}
@@ -600,6 +618,7 @@
mode_mask_ = mode_mask;
last_id_ = 0;
last_position_ = 0;
+ code_age_sequence_ = NULL;
if (mode_mask_ == 0) pos_ = end_;
next();
}
@@ -652,6 +671,8 @@
UNREACHABLE();
#endif
return "debug break slot";
+ case RelocInfo::CODE_AGE_SEQUENCE:
+ return "code_age_sequence";
case RelocInfo::NUMBER_OF_MODES:
UNREACHABLE();
return "number_of_modes";
@@ -739,6 +760,9 @@
case NUMBER_OF_MODES:
UNREACHABLE();
break;
+ case CODE_AGE_SEQUENCE:
+ ASSERT(Code::IsYoungSequence(pc_) || code_age_stub()->IsCode());
+ break;
}
}
#endif // VERIFY_HEAP
@@ -872,6 +896,13 @@
Isolate* isolate) {
return ExternalReference(Redirect(isolate,
FUNCTION_ADDR(JSDate::GetField)));
}
+
+
+ExternalReference ExternalReference::get_make_code_young_function(
+ Isolate* isolate) {
+ return ExternalReference(Redirect(
+ isolate, FUNCTION_ADDR(Code::MakeCodeAgeSequenceYoung)));
+}
ExternalReference ExternalReference::date_cache_stamp(Isolate* isolate) {
=======================================
--- /trunk/src/assembler.h Mon Oct 22 06:09:53 2012
+++ /trunk/src/assembler.h Mon Nov 12 06:53:34 2012
@@ -59,7 +59,13 @@
explicit AssemblerBase(Isolate* isolate);
Isolate* isolate() const { return isolate_; }
- int jit_cookie() { return jit_cookie_; }
+ int jit_cookie() const { return jit_cookie_; }
+
+ bool emit_debug_code() const { return emit_debug_code_; }
+ void set_emit_debug_code(bool value) { emit_debug_code_ = value; }
+
+ bool predictable_code_size() const { return predictable_code_size_; }
+ void set_predictable_code_size(bool value) { predictable_code_size_ =
value; }
// Overwrite a host NaN with a quiet target NaN. Used by mksnapshot for
// cross-snapshotting.
@@ -68,6 +74,28 @@
private:
Isolate* isolate_;
int jit_cookie_;
+ bool emit_debug_code_;
+ bool predictable_code_size_;
+};
+
+
+// Avoids using instructions that vary in size in unpredictable ways
between the
+// snapshot and the running VM.
+class PredictableCodeSizeScope {
+ public:
+ explicit PredictableCodeSizeScope(AssemblerBase* assembler)
+ : assembler_(assembler) {
+ old_value_ = assembler_->predictable_code_size();
+ assembler_->set_predictable_code_size(true);
+ }
+
+ ~PredictableCodeSizeScope() {
+ assembler_->set_predictable_code_size(old_value_);
+ }
+
+ private:
+ AssemblerBase* assembler_;
+ bool old_value_;
};
@@ -211,6 +239,12 @@
// Pseudo-types
NUMBER_OF_MODES, // There are at most 15 modes with noncompact
encoding.
NONE, // never recorded
+ CODE_AGE_SEQUENCE, // Not stored in RelocInfo array, used explictly by
+ // code aging.
+ FIRST_REAL_RELOC_MODE = CODE_TARGET,
+ LAST_REAL_RELOC_MODE = CONST_POOL,
+ FIRST_PSEUDO_RELOC_MODE = CODE_AGE_SEQUENCE,
+ LAST_PSEUDO_RELOC_MODE = CODE_AGE_SEQUENCE,
LAST_CODE_ENUM = DEBUG_BREAK,
LAST_GCED_ENUM = GLOBAL_PROPERTY_CELL,
// Modes <= LAST_COMPACT_ENUM are guaranteed to have compact encoding.
@@ -225,6 +259,15 @@
: pc_(pc), rmode_(rmode), data_(data), host_(host) {
}
+ static inline bool IsRealRelocMode(Mode mode) {
+ return mode >= FIRST_REAL_RELOC_MODE &&
+ mode <= LAST_REAL_RELOC_MODE;
+ }
+ static inline bool IsPseudoRelocMode(Mode mode) {
+ ASSERT(!IsRealRelocMode(mode));
+ return mode >= FIRST_PSEUDO_RELOC_MODE &&
+ mode <= LAST_PSEUDO_RELOC_MODE;
+ }
static inline bool IsConstructCall(Mode mode) {
return mode == CONSTRUCT_CALL;
}
@@ -262,6 +305,9 @@
static inline bool IsDebugBreakSlot(Mode mode) {
return mode == DEBUG_BREAK_SLOT;
}
+ static inline bool IsCodeAgeSequence(Mode mode) {
+ return mode == CODE_AGE_SEQUENCE;
+ }
static inline int ModeMask(Mode mode) { return 1 << mode; }
// Accessors
@@ -294,7 +340,8 @@
INLINE(Handle<JSGlobalPropertyCell> target_cell_handle());
INLINE(void set_target_cell(JSGlobalPropertyCell* cell,
WriteBarrierMode mode =
UPDATE_WRITE_BARRIER));
-
+ INLINE(Code* code_age_stub());
+ INLINE(void set_code_age_stub(Code* stub));
// Read the address of the word containing the target_address in an
// instruction stream. What this means exactly is
architecture-independent.
@@ -487,6 +534,7 @@
byte* pos_;
byte* end_;
+ byte* code_age_sequence_;
RelocInfo rinfo_;
bool done_;
int mode_mask_;
@@ -595,6 +643,8 @@
static ExternalReference get_date_field_function(Isolate* isolate);
static ExternalReference date_cache_stamp(Isolate* isolate);
+ static ExternalReference get_make_code_young_function(Isolate* isolate);
+
// Deoptimization support.
static ExternalReference new_deoptimizer_function(Isolate* isolate);
static ExternalReference compute_output_frames_function(Isolate*
isolate);
=======================================
--- /trunk/src/bootstrapper.cc Wed Nov 7 01:25:55 2012
+++ /trunk/src/bootstrapper.cc Mon Nov 12 06:53:34 2012
@@ -1415,6 +1415,11 @@
INSTALL_NATIVE(JSFunction, "DerivedSetTrap", derived_set_trap);
INSTALL_NATIVE(JSFunction, "ProxyEnumerate", proxy_enumerate);
}
+ if (FLAG_harmony_observation) {
+ INSTALL_NATIVE(JSFunction, "NotifyChange", observers_notify_change);
+ INSTALL_NATIVE(JSFunction, "DeliverChangeRecords",
+ observers_deliver_changes);
+ }
}
#undef INSTALL_NATIVE
@@ -1828,7 +1833,7 @@
"native collection.js") == 0) {
if (!CompileExperimentalBuiltin(isolate(), i)) return false;
}
- if (FLAG_harmony_object_observe &&
+ if (FLAG_harmony_observation &&
strcmp(ExperimentalNatives::GetScriptName(i).start(),
"native object-observe.js") == 0) {
if (!CompileExperimentalBuiltin(isolate(), i)) return false;
=======================================
--- /trunk/src/builtins.cc Wed Oct 10 10:07:22 2012
+++ /trunk/src/builtins.cc Mon Nov 12 06:53:34 2012
@@ -510,6 +510,10 @@
FixedArray* elms = FixedArray::cast(elms_obj);
JSArray* array = JSArray::cast(receiver);
+ if (FLAG_harmony_observation && array->map()->is_observed()) {
+ return CallJsBuiltin(isolate, "ArrayPush", args);
+ }
+
int len = Smi::cast(array->length())->value();
int to_add = args.length() - 1;
if (to_add == 0) {
@@ -566,11 +570,15 @@
FixedArray* elms = FixedArray::cast(elms_obj);
JSArray* array = JSArray::cast(receiver);
+ if (FLAG_harmony_observation && array->map()->is_observed()) {
+ return CallJsBuiltin(isolate, "ArrayPop", args);
+ }
+
int len = Smi::cast(array->length())->value();
if (len == 0) return heap->undefined_value();
// Get top element
- MaybeObject* top = elms->get(len - 1);
+ Object* top = elms->get(len - 1);
// Set the length.
array->set_length(Smi::FromInt(len - 1));
@@ -581,9 +589,7 @@
return top;
}
- top = array->GetPrototype()->GetElement(len - 1);
-
- return top;
+ return array->GetPrototype()->GetElement(len - 1);
}
@@ -604,6 +610,10 @@
JSArray* array = JSArray::cast(receiver);
ASSERT(array->HasFastSmiOrObjectElements());
+ if (FLAG_harmony_observation && array->map()->is_observed()) {
+ return CallJsBuiltin(isolate, "ArrayShift", args);
+ }
+
int len = Smi::cast(array->length())->value();
if (len == 0) return heap->undefined_value();
@@ -646,6 +656,10 @@
JSArray* array = JSArray::cast(receiver);
ASSERT(array->HasFastSmiOrObjectElements());
+ if (FLAG_harmony_observation && array->map()->is_observed()) {
+ return CallJsBuiltin(isolate, "ArrayUnshift", args);
+ }
+
int len = Smi::cast(array->length())->value();
int to_add = args.length() - 1;
int new_length = len + to_add;
@@ -802,6 +816,10 @@
JSArray* array = JSArray::cast(receiver);
ASSERT(array->HasFastSmiOrObjectElements());
+ if (FLAG_harmony_observation && array->map()->is_observed()) {
+ return CallJsBuiltin(isolate, "ArraySplice", args);
+ }
+
int len = Smi::cast(array->length())->value();
int n_arguments = args.length() - 1;
=======================================
--- /trunk/src/builtins.h Tue Sep 11 06:22:37 2012
+++ /trunk/src/builtins.h Mon Nov 12 06:53:34 2012
@@ -38,6 +38,25 @@
};
+#define CODE_AGE_LIST_WITH_ARG(V, A) \
+ V(Quadragenarian, A) \
+ V(Quinquagenarian, A) \
+ V(Sexagenarian, A) \
+ V(Septuagenarian, A) \
+ V(Octogenarian, A)
+
+#define CODE_AGE_LIST_IGNORE_ARG(X, V) V(X)
+
+#define CODE_AGE_LIST(V) \
+ CODE_AGE_LIST_WITH_ARG(CODE_AGE_LIST_IGNORE_ARG, V)
+
+#define DECLARE_CODE_AGE_BUILTIN(C, V) \
+ V(Make##C##CodeYoungAgainOddMarking, BUILTIN, \
+ UNINITIALIZED, Code::kNoExtraICState) \
+ V(Make##C##CodeYoungAgainEvenMarking, BUILTIN, \
+ UNINITIALIZED, Code::kNoExtraICState)
+
+
// Define list of builtins implemented in C++.
#define BUILTIN_LIST_C(V) \
V(Illegal, NO_EXTRA_ARGUMENTS) \
@@ -195,8 +214,8 @@
Code::kNoExtraICState) \
\
V(OnStackReplacement, BUILTIN, UNINITIALIZED, \
- Code::kNoExtraICState)
-
+ Code::kNoExtraICState) \
+ CODE_AGE_LIST_WITH_ARG(DECLARE_CODE_AGE_BUILTIN, V)
#ifdef ENABLE_DEBUGGER_SUPPORT
// Define list of builtins used by the debugger implemented in assembly.
@@ -379,6 +398,14 @@
static void Generate_StringConstructCode(MacroAssembler* masm);
static void Generate_OnStackReplacement(MacroAssembler* masm);
+#define DECLARE_CODE_AGE_BUILTIN_GENERATOR(C) \
+ static void Generate_Make##C##CodeYoungAgainEvenMarking( \
+ MacroAssembler* masm); \
+ static void Generate_Make##C##CodeYoungAgainOddMarking( \
+ MacroAssembler* masm);
+ CODE_AGE_LIST(DECLARE_CODE_AGE_BUILTIN_GENERATOR)
+#undef DECLARE_CODE_AGE_BUILTIN_GENERATOR
+
static void InitBuiltinFunctionTable();
bool initialized_;
=======================================
--- /trunk/src/code-stubs.h Wed Oct 10 10:07:22 2012
+++ /trunk/src/code-stubs.h Mon Nov 12 06:53:34 2012
@@ -1170,6 +1170,8 @@
// false on an attempt to replace a non-NULL entry hook with another
// non-NULL hook.
static bool SetFunctionEntryHook(FunctionEntryHook entry_hook);
+
+ static bool HasEntryHook() { return entry_hook_ != NULL; }
private:
static void EntryHookTrampoline(intptr_t function,
=======================================
--- /trunk/src/collection.js Wed Jun 27 04:12:38 2012
+++ /trunk/src/collection.js Mon Nov 12 06:53:34 2012
@@ -86,6 +86,25 @@
return false;
}
}
+
+
+function SetGetSize() {
+ if (!IS_SET(this)) {
+ throw MakeTypeError('incompatible_method_receiver',
+ ['Set.prototype.size', this]);
+ }
+ return %SetGetSize(this);
+}
+
+
+function SetClear() {
+ if (!IS_SET(this)) {
+ throw MakeTypeError('incompatible_method_receiver',
+ ['Set.prototype.clear', this]);
+ }
+ // Replace the internal table with a new empty table.
+ %SetInitialize(this);
+}
function MapConstructor() {
@@ -143,6 +162,25 @@
}
return %MapDelete(this, key);
}
+
+
+function MapGetSize() {
+ if (!IS_MAP(this)) {
+ throw MakeTypeError('incompatible_method_receiver',
+ ['Map.prototype.size', this]);
+ }
+ return %MapGetSize(this);
+}
+
+
+function MapClear() {
+ if (!IS_MAP(this)) {
+ throw MakeTypeError('incompatible_method_receiver',
+ ['Map.prototype.clear', this]);
+ }
+ // Replace the internal table with a new empty table.
+ %MapInitialize(this);
+}
function WeakMapConstructor() {
@@ -215,18 +253,22 @@
%SetProperty($Map.prototype, "constructor", $Map, DONT_ENUM);
// Set up the non-enumerable functions on the Set prototype object.
+ InstallGetter($Set.prototype, "size", SetGetSize);
InstallFunctions($Set.prototype, DONT_ENUM, $Array(
"add", SetAdd,
"has", SetHas,
- "delete", SetDelete
+ "delete", SetDelete,
+ "clear", SetClear
));
// Set up the non-enumerable functions on the Map prototype object.
+ InstallGetter($Map.prototype, "size", MapGetSize);
InstallFunctions($Map.prototype, DONT_ENUM, $Array(
"get", MapGet,
"set", MapSet,
"has", MapHas,
- "delete", MapDelete
+ "delete", MapDelete,
+ "clear", MapClear
));
// Set up the WeakMap constructor function.
=======================================
--- /trunk/src/compiler.cc Wed Nov 7 01:25:55 2012
+++ /trunk/src/compiler.cc Mon Nov 12 06:53:34 2012
@@ -609,6 +609,7 @@
if (result->ic_age() != HEAP->global_ic_age()) {
result->ResetForNewContext(HEAP->global_ic_age());
}
+ result->code()->MakeYoung();
}
if (result.is_null()) isolate->ReportPendingMessages();
@@ -670,6 +671,7 @@
if (result->ic_age() != HEAP->global_ic_age()) {
result->ResetForNewContext(HEAP->global_ic_age());
}
+ result->code()->MakeYoung();
}
return result;
=======================================
--- /trunk/src/contexts.h Wed Nov 7 01:25:55 2012
+++ /trunk/src/contexts.h Mon Nov 12 06:53:34 2012
@@ -161,7 +161,9 @@
V(DERIVED_HAS_TRAP_INDEX, JSFunction, derived_has_trap) \
V(DERIVED_GET_TRAP_INDEX, JSFunction, derived_get_trap) \
V(DERIVED_SET_TRAP_INDEX, JSFunction, derived_set_trap) \
- V(PROXY_ENUMERATE, JSFunction, proxy_enumerate) \
+ V(PROXY_ENUMERATE_INDEX, JSFunction, proxy_enumerate) \
+ V(OBSERVERS_NOTIFY_CHANGE_INDEX, JSFunction, observers_notify_change) \
+ V(OBSERVERS_DELIVER_CHANGES_INDEX, JSFunction,
observers_deliver_changes) \
V(RANDOM_SEED_INDEX, ByteArray, random_seed)
// JSFunctions are pairs (context, function code), sometimes also called
@@ -288,7 +290,9 @@
DERIVED_HAS_TRAP_INDEX,
DERIVED_GET_TRAP_INDEX,
DERIVED_SET_TRAP_INDEX,
- PROXY_ENUMERATE,
+ PROXY_ENUMERATE_INDEX,
+ OBSERVERS_NOTIFY_CHANGE_INDEX,
+ OBSERVERS_DELIVER_CHANGES_INDEX,
RANDOM_SEED_INDEX,
// Properties from here are treated as weak references by the full GC.
=======================================
--- /trunk/src/debug.cc Mon Oct 22 06:09:53 2012
+++ /trunk/src/debug.cc Mon Nov 12 06:53:34 2012
@@ -261,8 +261,12 @@
// Create relocation iterators for the two code objects.
if (reloc_iterator_ != NULL) delete reloc_iterator_;
if (reloc_iterator_original_ != NULL) delete reloc_iterator_original_;
- reloc_iterator_ = new RelocIterator(debug_info_->code());
- reloc_iterator_original_ = new
RelocIterator(debug_info_->original_code());
+ reloc_iterator_ = new RelocIterator(
+ debug_info_->code(),
+ ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE));
+ reloc_iterator_original_ = new RelocIterator(
+ debug_info_->original_code(),
+ ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE));
// Position at the first break point.
break_point_ = -1;
=======================================
--- /trunk/src/deoptimizer.cc Wed Oct 31 03:02:10 2012
+++ /trunk/src/deoptimizer.cc Mon Nov 12 06:53:34 2012
@@ -41,8 +41,11 @@
namespace internal {
DeoptimizerData::DeoptimizerData() {
- eager_deoptimization_entry_code_ = NULL;
- lazy_deoptimization_entry_code_ = NULL;
+ eager_deoptimization_entry_code_entries_ = -1;
+ lazy_deoptimization_entry_code_entries_ = -1;
+ size_t deopt_table_size = Deoptimizer::GetMaxDeoptTableSize();
+ eager_deoptimization_entry_code_ = new VirtualMemory(deopt_table_size);
+ lazy_deoptimization_entry_code_ = new VirtualMemory(deopt_table_size);
current_ = NULL;
deoptimizing_code_list_ = NULL;
#ifdef ENABLE_DEBUGGER_SUPPORT
@@ -52,16 +55,11 @@
DeoptimizerData::~DeoptimizerData() {
- if (eager_deoptimization_entry_code_ != NULL) {
- Isolate::Current()->memory_allocator()->Free(
- eager_deoptimization_entry_code_);
- eager_deoptimization_entry_code_ = NULL;
- }
- if (lazy_deoptimization_entry_code_ != NULL) {
- Isolate::Current()->memory_allocator()->Free(
- lazy_deoptimization_entry_code_);
- lazy_deoptimization_entry_code_ = NULL;
- }
+ delete eager_deoptimization_entry_code_;
+ eager_deoptimization_entry_code_ = NULL;
+ delete lazy_deoptimization_entry_code_;
+ lazy_deoptimization_entry_code_ = NULL;
+
DeoptimizingCodeListNode* current = deoptimizing_code_list_;
while (current != NULL) {
DeoptimizingCodeListNode* prev = current;
@@ -101,6 +99,20 @@
isolate->deoptimizer_data()->current_ = deoptimizer;
return deoptimizer;
}
+
+
+// No larger than 2K on all platforms
+static const int kDeoptTableMaxEpilogueCodeSize = 2 * KB;
+
+
+size_t Deoptimizer::GetMaxDeoptTableSize() {
+ int entries_size =
+ Deoptimizer::kMaxNumberOfEntries * Deoptimizer::table_entry_size_;
+ int commit_page_size = static_cast<int>(OS::CommitPageSize());
+ int page_count = ((kDeoptTableMaxEpilogueCodeSize + entries_size - 1) /
+ commit_page_size) + 1;
+ return static_cast<size_t>(commit_page_size * page_count);
+}
Deoptimizer* Deoptimizer::Grab(Isolate* isolate) {
@@ -461,44 +473,45 @@
}
-Address Deoptimizer::GetDeoptimizationEntry(int id, BailoutType type) {
+Address Deoptimizer::GetDeoptimizationEntry(int id,
+ BailoutType type,
+ GetEntryMode mode) {
ASSERT(id >= 0);
- if (id >= kNumberOfEntries) return NULL;
- MemoryChunk* base = NULL;
+ if (id >= kMaxNumberOfEntries) return NULL;
+ VirtualMemory* base = NULL;
+ if (mode == ENSURE_ENTRY_CODE) {
+ EnsureCodeForDeoptimizationEntry(type, id);
+ } else {
+ ASSERT(mode == CALCULATE_ENTRY_ADDRESS);
+ }
DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
if (type == EAGER) {
- if (data->eager_deoptimization_entry_code_ == NULL) {
- data->eager_deoptimization_entry_code_ = CreateCode(type);
- }
base = data->eager_deoptimization_entry_code_;
} else {
- if (data->lazy_deoptimization_entry_code_ == NULL) {
- data->lazy_deoptimization_entry_code_ = CreateCode(type);
- }
base = data->lazy_deoptimization_entry_code_;
}
return
- static_cast<Address>(base->area_start()) + (id * table_entry_size_);
+ static_cast<Address>(base->address()) + (id * table_entry_size_);
}
int Deoptimizer::GetDeoptimizationId(Address addr, BailoutType type) {
- MemoryChunk* base = NULL;
+ VirtualMemory* base = NULL;
DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
if (type == EAGER) {
base = data->eager_deoptimization_entry_code_;
} else {
base = data->lazy_deoptimization_entry_code_;
}
+ Address base_casted = reinterpret_cast<Address>(base->address());
if (base == NULL ||
- addr < base->area_start() ||
- addr >= base->area_start() +
- (kNumberOfEntries * table_entry_size_)) {
+ addr < base->address() ||
+ addr >= base_casted + (kMaxNumberOfEntries * table_entry_size_)) {
return kNotDeoptimizationEntry;
}
ASSERT_EQ(0,
- static_cast<int>(addr - base->area_start()) % table_entry_size_);
- return static_cast<int>(addr - base->area_start()) / table_entry_size_;
+ static_cast<int>(addr - base_casted) % table_entry_size_);
+ return static_cast<int>(addr - base_casted) / table_entry_size_;
}
@@ -1384,31 +1397,44 @@
}
-MemoryChunk* Deoptimizer::CreateCode(BailoutType type) {
+void Deoptimizer::EnsureCodeForDeoptimizationEntry(BailoutType type,
+ int max_entry_id) {
// We cannot run this if the serializer is enabled because this will
// cause us to emit relocation information for the external
// references. This is fine because the deoptimizer's code section
// isn't meant to be serialized at all.
ASSERT(!Serializer::enabled());
+ ASSERT(type == EAGER || type == LAZY);
+ DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
+ int entry_count = (type == EAGER)
+ ? data->eager_deoptimization_entry_code_entries_
+ : data->lazy_deoptimization_entry_code_entries_;
+ if (max_entry_id < entry_count) return;
+ entry_count = Min(Max(entry_count * 2, Deoptimizer::kMinNumberOfEntries),
+ Deoptimizer::kMaxNumberOfEntries);
+
MacroAssembler masm(Isolate::Current(), NULL, 16 * KB);
masm.set_emit_debug_code(false);
- GenerateDeoptimizationEntries(&masm, kNumberOfEntries, type);
+ GenerateDeoptimizationEntries(&masm, entry_count, type);
CodeDesc desc;
masm.GetCode(&desc);
ASSERT(desc.reloc_size == 0);
- MemoryChunk* chunk =
-
Isolate::Current()->memory_allocator()->AllocateChunk(desc.instr_size,
- EXECUTABLE,
- NULL);
- ASSERT(chunk->area_size() >= desc.instr_size);
- if (chunk == NULL) {
- V8::FatalProcessOutOfMemory("Not enough memory for deoptimization
table");
+ VirtualMemory* memory = type == EAGER
+ ? data->eager_deoptimization_entry_code_
+ : data->lazy_deoptimization_entry_code_;
+ size_t table_size = Deoptimizer::GetMaxDeoptTableSize();
+ ASSERT(static_cast<int>(table_size) >= desc.instr_size);
+ memory->Commit(memory->address(), table_size, true);
+ memcpy(memory->address(), desc.buffer, desc.instr_size);
+ CPU::FlushICache(memory->address(), desc.instr_size);
+
+ if (type == EAGER) {
+ data->eager_deoptimization_entry_code_entries_ = entry_count;
+ } else {
+ data->lazy_deoptimization_entry_code_entries_ = entry_count;
}
- memcpy(chunk->area_start(), desc.buffer, desc.instr_size);
- CPU::FlushICache(chunk->area_start(), desc.instr_size);
- return chunk;
}
=======================================
--- /trunk/src/deoptimizer.h Mon Oct 22 06:09:53 2012
+++ /trunk/src/deoptimizer.h Mon Nov 12 06:53:34 2012
@@ -100,8 +100,10 @@
#endif
private:
- MemoryChunk* eager_deoptimization_entry_code_;
- MemoryChunk* lazy_deoptimization_entry_code_;
+ int eager_deoptimization_entry_code_entries_;
+ int lazy_deoptimization_entry_code_entries_;
+ VirtualMemory* eager_deoptimization_entry_code_;
+ VirtualMemory* lazy_deoptimization_entry_code_;
Deoptimizer* current_;
#ifdef ENABLE_DEBUGGER_SUPPORT
@@ -226,7 +228,17 @@
static void ComputeOutputFrames(Deoptimizer* deoptimizer);
- static Address GetDeoptimizationEntry(int id, BailoutType type);
+
+ enum GetEntryMode {
+ CALCULATE_ENTRY_ADDRESS,
+ ENSURE_ENTRY_CODE
+ };
+
+
+ static Address GetDeoptimizationEntry(
+ int id,
+ BailoutType type,
+ GetEntryMode mode = ENSURE_ENTRY_CODE);
static int GetDeoptimizationId(Address addr, BailoutType type);
static int GetOutputInfo(DeoptimizationOutputData* data,
BailoutId node_id,
@@ -283,8 +295,11 @@
int ConvertJSFrameIndexToFrameIndex(int jsframe_index);
+ static size_t GetMaxDeoptTableSize();
+
private:
- static const int kNumberOfEntries = 16384;
+ static const int kMinNumberOfEntries = 64;
+ static const int kMaxNumberOfEntries = 16384;
Deoptimizer(Isolate* isolate,
JSFunction* function,
@@ -327,7 +342,8 @@
void AddArgumentsObjectValue(intptr_t value);
void AddDoubleValue(intptr_t slot_address, double value);
- static MemoryChunk* CreateCode(BailoutType type);
+ static void EnsureCodeForDeoptimizationEntry(BailoutType type,
+ int max_entry_id);
static void GenerateDeoptimizationEntries(
MacroAssembler* masm, int count, BailoutType type);
=======================================
--- /trunk/src/elements.cc Tue Nov 6 04:13:00 2012
+++ /trunk/src/elements.cc Mon Nov 12 06:53:34 2012
@@ -528,9 +528,8 @@
JSObject* holder,
uint32_t key,
BackingStore* backing_store) {
- MaybeObject* element =
- ElementsAccessorSubclass::GetImpl(receiver, holder, key,
backing_store);
- return !element->IsTheHole();
+ return ElementsAccessorSubclass::GetAttributesImpl(
+ receiver, holder, key, backing_store) != ABSENT;
}
virtual bool HasElement(Object* receiver,
@@ -564,6 +563,29 @@
: backing_store->GetHeap()->the_hole_value();
}
+ MUST_USE_RESULT virtual PropertyAttributes GetAttributes(
+ Object* receiver,
+ JSObject* holder,
+ uint32_t key,
+ FixedArrayBase* backing_store) {
+ if (backing_store == NULL) {
+ backing_store = holder->elements();
+ }
+ return ElementsAccessorSubclass::GetAttributesImpl(
+ receiver, holder, key, BackingStore::cast(backing_store));
+ }
+
+ MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
+ Object* receiver,
+ JSObject* obj,
+ uint32_t key,
+ BackingStore* backing_store) {
+ if (key >= ElementsAccessorSubclass::GetCapacityImpl(backing_store)) {
+ return ABSENT;
+ }
+ return backing_store->is_the_hole(key) ? ABSENT : NONE;
+ }
+
MUST_USE_RESULT virtual MaybeObject* SetLength(JSArray* array,
Object* length) {
return ElementsAccessorSubclass::SetLengthImpl(
@@ -1142,6 +1164,16 @@
? backing_store->get(key)
: backing_store->GetHeap()->undefined_value();
}
+
+ MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
+ Object* receiver,
+ JSObject* obj,
+ uint32_t key,
+ BackingStore* backing_store) {
+ return
+ key <
ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store)
+ ? NONE : ABSENT;
+ }
MUST_USE_RESULT static MaybeObject* SetLengthImpl(
JSObject* obj,
@@ -1430,6 +1462,18 @@
}
return obj->GetHeap()->the_hole_value();
}
+
+ MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
+ Object* receiver,
+ JSObject* obj,
+ uint32_t key,
+ SeededNumberDictionary* backing_store) {
+ int entry = backing_store->FindEntry(key);
+ if (entry != SeededNumberDictionary::kNotFound) {
+ return backing_store->DetailsAt(entry).attributes();
+ }
+ return ABSENT;
+ }
static bool HasElementImpl(Object* receiver,
JSObject* holder,
@@ -1489,6 +1533,22 @@
}
}
}
+
+ MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
+ Object* receiver,
+ JSObject* obj,
+ uint32_t key,
+ FixedArray* parameter_map) {
+ Object* probe = GetParameterMapArg(obj, parameter_map, key);
+ if (!probe->IsTheHole()) {
+ return NONE;
+ } else {
+ // If not aliased, check the arguments.
+ FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
+ return ElementsAccessor::ForArray(arguments)->GetAttributes(
+ receiver, obj, key, arguments);
+ }
+ }
MUST_USE_RESULT static MaybeObject* SetLengthImpl(
JSObject* obj,
=======================================
--- /trunk/src/elements.h Tue May 29 06:20:14 2012
+++ /trunk/src/elements.h Mon Nov 12 06:53:34 2012
@@ -71,6 +71,17 @@
uint32_t key,
FixedArrayBase* backing_store = NULL) = 0;
+ // Returns an element's attributes, or ABSENT if there is no such
+ // element. This method doesn't iterate up the prototype chain. The
caller
+ // can optionally pass in the backing store to use for the check, which
must
+ // be compatible with the ElementsKind of the ElementsAccessor. If
+ // backing_store is NULL, the holder->elements() is used as the backing
store.
+ MUST_USE_RESULT virtual PropertyAttributes GetAttributes(
+ Object* receiver,
+ JSObject* holder,
+ uint32_t key,
+ FixedArrayBase* backing_store = NULL) = 0;
+
// Modifies the length data property as specified for JSArrays and
resizes the
// underlying backing store accordingly. The method honors the semantics
of
// changing array sizes as defined in EcmaScript 5.1 15.4.5.2, i.e.
array that
=======================================
--- /trunk/src/flag-definitions.h Tue Nov 6 04:13:00 2012
+++ /trunk/src/flag-definitions.h Mon Nov 12 06:53:34 2012
@@ -144,16 +144,16 @@
DEFINE_bool(harmony_proxies, false, "enable harmony proxies")
DEFINE_bool(harmony_collections, false,
"enable harmony collections (sets, maps, and weak maps)")
-DEFINE_bool(harmony_object_observe, false,
+DEFINE_bool(harmony_observation, false,
"enable harmony object observation (implies harmony
collections")
DEFINE_bool(harmony, false, "enable all harmony features (except typeof)")
DEFINE_implication(harmony, harmony_scoping)
DEFINE_implication(harmony, harmony_modules)
DEFINE_implication(harmony, harmony_proxies)
DEFINE_implication(harmony, harmony_collections)
-DEFINE_implication(harmony, harmony_object_observe)
+DEFINE_implication(harmony, harmony_observation)
DEFINE_implication(harmony_modules, harmony_scoping)
-DEFINE_implication(harmony_object_observe, harmony_collections)
+DEFINE_implication(harmony_observation, harmony_collections)
// Flags for experimental implementation features.
DEFINE_bool(packed_arrays, true, "optimizes arrays that have no holes")
@@ -396,6 +396,9 @@
"flush code that we expect not to use again (during full gc)")
DEFINE_bool(flush_code_incrementally, false,
"flush code that we expect not to use again (incrementally)")
+DEFINE_bool(age_code, false,
+ "track un-executed functions to age code and flush only "
+ "old code")
DEFINE_bool(incremental_marking, true, "use incremental marking")
DEFINE_bool(incremental_marking_steps, true, "do incremental marking
steps")
DEFINE_bool(trace_incremental_marking, false,
=======================================
--- /trunk/src/global-handles.cc Mon Oct 22 06:09:53 2012
+++ /trunk/src/global-handles.cc Mon Nov 12 06:53:34 2012
@@ -69,6 +69,7 @@
class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
index_ = 0;
independent_ = false;
+ partially_dependent_ = false;
in_new_space_list_ = false;
parameter_or_next_free_.next_free = NULL;
callback_ = NULL;
@@ -89,6 +90,7 @@
object_ = object;
class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
independent_ = false;
+ partially_dependent_ = false;
state_ = NORMAL;
parameter_or_next_free_.parameter = NULL;
callback_ = NULL;
@@ -153,6 +155,15 @@
independent_ = true;
}
bool is_independent() const { return independent_; }
+
+ void MarkPartiallyDependent(GlobalHandles* global_handles) {
+ ASSERT(state_ != FREE);
+ if (global_handles->isolate()->heap()->InNewSpace(object_)) {
+ partially_dependent_ = true;
+ }
+ }
+ bool is_partially_dependent() const { return partially_dependent_; }
+ void clear_partially_dependent() { partially_dependent_ = false; }
// In-new-space-list flag accessors.
void set_in_new_space_list(bool v) { in_new_space_list_ = v; }
@@ -260,6 +271,7 @@
State state_ : 4;
bool independent_ : 1;
+ bool partially_dependent_ : 1;
bool in_new_space_list_ : 1;
// Handle specific callback.
@@ -446,6 +458,11 @@
void GlobalHandles::MarkIndependent(Object** location) {
Node::FromLocation(location)->MarkIndependent();
}
+
+
+void GlobalHandles::MarkPartiallyDependent(Object** location) {
+ Node::FromLocation(location)->MarkPartiallyDependent(this);
+}
bool GlobalHandles::IsIndependent(Object** location) {
@@ -501,8 +518,9 @@
for (int i = 0; i < new_space_nodes_.length(); ++i) {
Node* node = new_space_nodes_[i];
if (node->IsStrongRetainer() ||
- (node->IsWeakRetainer() && !node->is_independent())) {
- v->VisitPointer(node->location());
+ (node->IsWeakRetainer() && !node->is_independent() &&
+ !node->is_partially_dependent())) {
+ v->VisitPointer(node->location());
}
}
}
@@ -513,8 +531,8 @@
for (int i = 0; i < new_space_nodes_.length(); ++i) {
Node* node = new_space_nodes_[i];
ASSERT(node->is_in_new_space_list());
- if (node->is_independent() && node->IsWeak() &&
- f(isolate_->heap(), node->location())) {
+ if ((node->is_independent() || node->is_partially_dependent()) &&
+ node->IsWeak() && f(isolate_->heap(), node->location())) {
node->MarkPending();
}
}
@@ -525,7 +543,8 @@
for (int i = 0; i < new_space_nodes_.length(); ++i) {
Node* node = new_space_nodes_[i];
ASSERT(node->is_in_new_space_list());
- if (node->is_independent() && node->IsWeakRetainer()) {
+ if ((node->is_independent() || node->is_partially_dependent()) &&
+ node->IsWeakRetainer()) {
v->VisitPointer(node->location());
}
}
@@ -547,7 +566,10 @@
// Skip dependent handles. Their weak callbacks might expect to be
// called between two global garbage collection callbacks which
// are not called for minor collections.
- if (!node->is_independent()) continue;
+ if (!node->is_independent() && !node->is_partially_dependent()) {
+ continue;
+ }
+ node->clear_partially_dependent();
if (node->PostGarbageCollectionProcessing(isolate_, this)) {
if (initial_post_gc_processing_count != post_gc_processing_count_)
{
// Weak callback triggered another GC and another round of
@@ -563,6 +585,7 @@
}
} else {
for (NodeIterator it(this); !it.done(); it.Advance()) {
+ it.node()->clear_partially_dependent();
if (it.node()->PostGarbageCollectionProcessing(isolate_, this)) {
if (initial_post_gc_processing_count != post_gc_processing_count_)
{
// See the comment above.
@@ -610,7 +633,7 @@
void GlobalHandles::IterateAllRootsWithClassIds(ObjectVisitor* v) {
for (NodeIterator it(this); !it.done(); it.Advance()) {
- if (it.node()->has_wrapper_class_id() && it.node()->IsRetainer()) {
+ if (it.node()->IsRetainer() && it.node()->has_wrapper_class_id()) {
v->VisitEmbedderReference(it.node()->location(),
it.node()->wrapper_class_id());
}
=======================================
--- /trunk/src/global-handles.h Mon Oct 22 06:09:53 2012
+++ /trunk/src/global-handles.h Mon Nov 12 06:53:34 2012
@@ -155,6 +155,9 @@
// Clear the weakness of a global handle.
void MarkIndependent(Object** location);
+ // Mark the reference to this object externaly unreachable.
+ void MarkPartiallyDependent(Object** location);
+
static bool IsIndependent(Object** location);
// Tells whether global handle is near death.
@@ -195,16 +198,17 @@
// Iterates over strong and dependent handles. See the node above.
void IterateNewSpaceStrongAndDependentRoots(ObjectVisitor* v);
- // Finds weak independent handles satisfying the callback predicate
- // and marks them as pending. See the note above.
+ // Finds weak independent or partially independent handles satisfying
+ // the callback predicate and marks them as pending. See the note above.
void IdentifyNewSpaceWeakIndependentHandles(WeakSlotCallbackWithHeap f);
- // Iterates over weak independent handles. See the note above.
+ // Iterates over weak independent or partially independent handles.
+ // See the note above.
void IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v);
// Add an object group.
// Should be only used in GC callback function before a collection.
- // All groups are destroyed after a mark-compact collection.
+ // All groups are destroyed after a garbage collection.
void AddObjectGroup(Object*** handles,
size_t length,
v8::RetainedObjectInfo* info);
=======================================
--- /trunk/src/handles.cc Wed Oct 10 10:07:22 2012
+++ /trunk/src/handles.cc Mon Nov 12 06:53:34 2012
@@ -591,6 +591,25 @@
}
return result;
}
+
+
+Handle<Object> GetScriptNameOrSourceURL(Handle<Script> script) {
+ Isolate* isolate = script->GetIsolate();
+ Handle<String> name_or_source_url_key =
+ isolate->factory()->LookupAsciiSymbol("nameOrSourceURL");
+ Handle<JSValue> script_wrapper = GetScriptWrapper(script);
+ Handle<Object> property = GetProperty(script_wrapper,
+ name_or_source_url_key);
+ ASSERT(property->IsJSFunction());
+ Handle<JSFunction> method = Handle<JSFunction>::cast(property);
+ bool caught_exception;
+ Handle<Object> result = Execution::TryCall(method, script_wrapper, 0,
+ NULL, &caught_exception);
+ if (caught_exception) {
+ result = isolate->factory()->undefined_value();
+ }
+ return result;
+}
static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
=======================================
--- /trunk/src/handles.h Tue Oct 9 10:00:13 2012
+++ /trunk/src/handles.h Mon Nov 12 06:53:34 2012
@@ -93,6 +93,13 @@
private:
T** location_;
};
+
+
+// Convenience wrapper.
+template<class T>
+inline Handle<T> handle(T* t) {
+ return Handle<T>(t);
+}
class DeferredHandles;
@@ -260,6 +267,7 @@
// The safe version does not make heap allocations but may work much
slower.
int GetScriptLineNumberSafe(Handle<Script> script, int code_position);
int GetScriptColumnNumber(Handle<Script> script, int code_position);
+Handle<Object> GetScriptNameOrSourceURL(Handle<Script> script);
// Computes the enumerable keys from interceptors. Used for debug mirrors
and
// by GetKeysInFixedArrayFor below.
=======================================
--- /trunk/src/heap.cc Wed Nov 7 01:25:55 2012
+++ /trunk/src/heap.cc Mon Nov 12 06:53:34 2012
@@ -1333,6 +1333,12 @@
scavenge_visitor.VisitPointer(BitCast<Object**>(&native_contexts_list_));
new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
+
+ while (IterateObjectGroups(&scavenge_visitor)) {
+ new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
+ }
+ isolate()->global_handles()->RemoveObjectGroups();
+
isolate_->global_handles()->IdentifyNewSpaceWeakIndependentHandles(
&IsUnscavengedHeapObject);
isolate_->global_handles()->IterateNewSpaceWeakIndependentRoots(
@@ -1371,6 +1377,51 @@
scavenges_since_last_idle_round_++;
}
+
+
+// TODO(mstarzinger): Unify this method with
+// MarkCompactCollector::MarkObjectGroups().
+bool Heap::IterateObjectGroups(ObjectVisitor* scavenge_visitor) {
+ List<ObjectGroup*>* object_groups =
+ isolate()->global_handles()->object_groups();
+
+ int last = 0;
+ bool changed = false;
+ for (int i = 0; i < object_groups->length(); i++) {
+ ObjectGroup* entry = object_groups->at(i);
+ ASSERT(entry != NULL);
+
+ Object*** objects = entry->objects_;
+ bool group_marked = false;
+ for (size_t j = 0; j < entry->length_; j++) {
+ Object* object = *objects[j];
+ if (object->IsHeapObject()) {
+ if (!IsUnscavengedHeapObject(this, &object)) {
+ group_marked = true;
+ break;
+ }
+ }
+ }
+
+ if (!group_marked) {
+ (*object_groups)[last++] = entry;
+ continue;
+ }
+
+ for (size_t j = 0; j < entry->length_; ++j) {
+ Object* object = *objects[j];
+ if (object->IsHeapObject()) {
+ scavenge_visitor->VisitPointer(&object);
+ changed = true;
+ }
+ }
+
+ entry->Dispose();
+ object_groups->at(i) = NULL;
+ }
+ object_groups->Rewind(last);
+ return changed;
+}
String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap,
@@ -2844,6 +2895,15 @@
}
set_natives_source_cache(FixedArray::cast(obj));
+ // Allocate object to hold object observation state.
+ { MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE,
JSObject::kHeaderSize);
+ if (!maybe_obj->ToObject(&obj)) return false;
+ }
+ { MaybeObject* maybe_obj = AllocateJSObjectFromMap(Map::cast(obj));
+ if (!maybe_obj->ToObject(&obj)) return false;
+ }
+ set_observation_state(JSObject::cast(obj));
+
// Handling of script id generation is in FACTORY->NewScript.
set_last_script_id(undefined_value());
@@ -2861,6 +2921,34 @@
return true;
}
+
+
+bool Heap::RootCanBeWrittenAfterInitialization(Heap::RootListIndex
root_index) {
+ RootListIndex writable_roots[] = {
+ kStoreBufferTopRootIndex,
+ kStackLimitRootIndex,
+ kInstanceofCacheFunctionRootIndex,
+ kInstanceofCacheMapRootIndex,
+ kInstanceofCacheAnswerRootIndex,
+ kCodeStubsRootIndex,
+ kNonMonomorphicCacheRootIndex,
+ kPolymorphicCodeCacheRootIndex,
+ kLastScriptIdRootIndex,
+ kEmptyScriptRootIndex,
+ kRealStackLimitRootIndex,
+ kArgumentsAdaptorDeoptPCOffsetRootIndex,
+ kConstructStubDeoptPCOffsetRootIndex,
+ kGetterStubDeoptPCOffsetRootIndex,
+ kSetterStubDeoptPCOffsetRootIndex,
+ kSymbolTableRootIndex,
+ };
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(writable_roots); i++) {
+ if (root_index == writable_roots[i])
+ return true;
+ }
+ return false;
+}
Object* RegExpResultsCache::Lookup(Heap* heap,
=======================================
--- /trunk/src/heap.h Wed Nov 7 01:25:55 2012
+++ /trunk/src/heap.h Mon Nov 12 06:53:34 2012
@@ -154,7 +154,8 @@
V(Smi, arguments_adaptor_deopt_pc_offset,
ArgumentsAdaptorDeoptPCOffset) \
V(Smi, construct_stub_deopt_pc_offset,
ConstructStubDeoptPCOffset) \
V(Smi, getter_stub_deopt_pc_offset,
GetterStubDeoptPCOffset) \
- V(Smi, setter_stub_deopt_pc_offset, SetterStubDeoptPCOffset)
+ V(Smi, setter_stub_deopt_pc_offset,
SetterStubDeoptPCOffset) \
+ V(JSObject, observation_state, ObservationState)
#define ROOT_LIST(V) \
STRONG_ROOT_LIST(V) \
@@ -1451,6 +1452,10 @@
STATIC_CHECK(kFalseValueRootIndex == Internals::kFalseValueRootIndex);
STATIC_CHECK(kempty_symbolRootIndex == Internals::kEmptySymbolRootIndex);
+ // Generated code can embed direct references to non-writable roots if
+ // they are in new space.
+ static bool RootCanBeWrittenAfterInitialization(RootListIndex
root_index);
+
MUST_USE_RESULT MaybeObject* NumberToString(
Object* number, bool check_number_string_cache = true);
MUST_USE_RESULT MaybeObject* Uint32ToString(
@@ -1902,6 +1907,7 @@
bool PerformGarbageCollection(GarbageCollector collector,
GCTracer* tracer);
+ bool IterateObjectGroups(ObjectVisitor* scavenge_visitor);
inline void UpdateOldSpaceLimits();
=======================================
--- /trunk/src/ia32/assembler-ia32-inl.h Mon Oct 22 06:09:53 2012
+++ /trunk/src/ia32/assembler-ia32-inl.h Mon Nov 12 06:53:34 2012
@@ -46,12 +46,21 @@
namespace internal {
+static const byte kCallOpcode = 0xE8;
+
+
// The modes possibly affected by apply must be in kApplyMask.
void RelocInfo::apply(intptr_t delta) {
if (rmode_ == RUNTIME_ENTRY || IsCodeTarget(rmode_)) {
int32_t* p = reinterpret_cast<int32_t*>(pc_);
*p -= delta; // Relocate entry.
CPU::FlushICache(p, sizeof(uint32_t));
+ } else if (rmode_ == CODE_AGE_SEQUENCE) {
+ if (*pc_ == kCallOpcode) {
+ int32_t* p = reinterpret_cast<int32_t*>(pc_ + 1);
+ *p -= delta; // Relocate entry.
+ CPU::FlushICache(p, sizeof(uint32_t));
+ }
} else if (rmode_ == JS_RETURN && IsPatchedReturnSequence()) {
// Special handling of js_return when a break point is set (call
// instruction has been inserted).
@@ -167,6 +176,21 @@
host(), NULL, cell);
}
}
+
+
+Code* RelocInfo::code_age_stub() {
+ ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
+ ASSERT(*pc_ == kCallOpcode);
+ return Code::GetCodeFromTargetAddress(
+ Assembler::target_address_at(pc_ + 1));
+}
+
+
+void RelocInfo::set_code_age_stub(Code* stub) {
+ ASSERT(*pc_ == kCallOpcode);
+ ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
+ Assembler::set_target_address_at(pc_ + 1, stub->instruction_start());
+}
Address RelocInfo::call_address() {
@@ -206,7 +230,7 @@
bool RelocInfo::IsPatchedReturnSequence() {
- return *pc_ == 0xE8;
+ return *pc_ == kCallOpcode;
}
@@ -227,7 +251,9 @@
} else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
visitor->VisitExternalReference(this);
CPU::FlushICache(pc_, sizeof(Address));
-#ifdef ENABLE_DEBUGGER_SUPPORT
+ } else if (RelocInfo::IsCodeAgeSequence(mode)) {
+ visitor->VisitCodeAgeSequence(this);
+ #ifdef ENABLE_DEBUGGER_SUPPORT
// TODO(isolates): Get a cached isolate below.
} else if (((RelocInfo::IsJSReturn(mode) &&
IsPatchedReturnSequence()) ||
@@ -255,6 +281,8 @@
} else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
StaticVisitor::VisitExternalReference(this);
CPU::FlushICache(pc_, sizeof(Address));
+ } else if (RelocInfo::IsCodeAgeSequence(mode)) {
+ StaticVisitor::VisitCodeAgeSequence(heap, this);
#ifdef ENABLE_DEBUGGER_SUPPORT
} else if (heap->isolate()->debug()->has_break_points() &&
((RelocInfo::IsJSReturn(mode) &&
=======================================
--- /trunk/src/ia32/assembler-ia32.cc Tue Nov 6 04:13:00 2012
+++ /trunk/src/ia32/assembler-ia32.cc Mon Nov 12 06:53:34 2012
@@ -169,7 +169,7 @@
const int RelocInfo::kApplyMask =
RelocInfo::kCodeTargetMask | 1 << RelocInfo::RUNTIME_ENTRY |
1 << RelocInfo::JS_RETURN | 1 << RelocInfo::INTERNAL_REFERENCE |
- 1 << RelocInfo::DEBUG_BREAK_SLOT;
+ 1 << RelocInfo::DEBUG_BREAK_SLOT | 1 << RelocInfo::CODE_AGE_SEQUENCE;
bool RelocInfo::IsCodedSpecially() {
@@ -314,8 +314,7 @@
Assembler::Assembler(Isolate* arg_isolate, void* buffer, int buffer_size)
: AssemblerBase(arg_isolate),
- positions_recorder_(this),
- emit_debug_code_(FLAG_debug_code) {
+ positions_recorder_(this) {
if (buffer == NULL) {
// Do our own buffer management.
if (buffer_size <= kMinimalBufferSize) {
=======================================
--- /trunk/src/ia32/assembler-ia32.h Tue Nov 6 04:13:00 2012
+++ /trunk/src/ia32/assembler-ia32.h Mon Nov 12 06:53:34 2012
@@ -583,14 +583,6 @@
// TODO(vitalyr): the assembler does not need an isolate.
Assembler(Isolate* isolate, void* buffer, int buffer_size);
~Assembler();
-
- // Overrides the default provided by FLAG_debug_code.
- void set_emit_debug_code(bool value) { emit_debug_code_ = value; }
-
- // Avoids using instructions that vary in size in unpredictable ways
between
- // the snapshot and the running VM. This is needed by the full compiler
so
- // that it can recompile code with debug support and fix the PC.
- void set_predictable_code_size(bool value) { predictable_code_size_ =
value; }
// GetCode emits any pending (non-emitted) code and fills the descriptor
// desc. GetCode() is idempotent; it returns the same result if no other
@@ -1125,9 +1117,6 @@
void set_byte_at(int pos, byte value) { buffer_[pos] = value; }
protected:
- bool emit_debug_code() const { return emit_debug_code_; }
- bool predictable_code_size() const { return predictable_code_size_ ; }
-
void movsd(XMMRegister dst, const Operand& src);
void movsd(const Operand& dst, XMMRegister src);
@@ -1200,10 +1189,6 @@
RelocInfoWriter reloc_info_writer;
PositionsRecorder positions_recorder_;
-
- bool emit_debug_code_;
- bool predictable_code_size_;
-
friend class PositionsRecorder;
};
=======================================
--- /trunk/src/ia32/builtins-ia32.cc Tue Aug 28 02:06:19 2012
+++ /trunk/src/ia32/builtins-ia32.cc Mon Nov 12 06:53:34 2012
@@ -538,6 +538,42 @@
}
+static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
+ // For now, we are relying on the fact that make_code_young doesn't do
any
+ // garbage collection which allows us to save/restore the registers
without
+ // worrying about which of them contain pointers. We also don't build an
+ // internal frame to make the code faster, since we shouldn't have to do
stack
+ // crawls in MakeCodeYoung. This seems a bit fragile.
+
+ // Re-execute the code that was patched back to the young age when
+ // the stub returns.
+ __ sub(Operand(esp, 0), Immediate(5));
+ __ pushad();
+ __ mov(eax, Operand(esp, 8 * kPointerSize));
+ {
+ FrameScope scope(masm, StackFrame::MANUAL);
+ __ PrepareCallCFunction(1, ebx);
+ __ mov(Operand(esp, 0), eax);
+ __ CallCFunction(
+ ExternalReference::get_make_code_young_function(masm->isolate()),
1);
+ }
+ __ popad();
+ __ ret(0);
+}
+
+#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \
+void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \
+ MacroAssembler* masm) { \
+ GenerateMakeCodeYoungAgainCommon(masm); \
+} \
+void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \
+ MacroAssembler* masm) { \
+ GenerateMakeCodeYoungAgainCommon(masm); \
+}
+CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
+#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
+
+
static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
Deoptimizer::BailoutType
type) {
{
=======================================
***Additional files exist in this changeset.***