Revision: 4068
Author: [email protected]
Date: Tue Mar 9 07:43:04 2010
Log: Always invoke C++ ArrayPush builtin.
Now this builtin checks if it should go into fast case or resort to JS
ArrayPush builtin.
Review URL: http://codereview.chromium.org/660298
http://code.google.com/p/v8/source/detail?r=4068
Modified:
/branches/bleeding_edge/src/arm/stub-cache-arm.cc
/branches/bleeding_edge/src/bootstrapper.cc
/branches/bleeding_edge/src/builtins.cc
/branches/bleeding_edge/src/contexts.h
/branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
/branches/bleeding_edge/src/ic.cc
/branches/bleeding_edge/src/stub-cache.cc
/branches/bleeding_edge/src/stub-cache.h
/branches/bleeding_edge/src/top.cc
/branches/bleeding_edge/src/top.h
/branches/bleeding_edge/src/x64/stub-cache-x64.cc
/branches/bleeding_edge/test/cctest/test-serialize.cc
=======================================
--- /branches/bleeding_edge/src/arm/stub-cache-arm.cc Wed Feb 24 00:33:51
2010
+++ /branches/bleeding_edge/src/arm/stub-cache-arm.cc Tue Mar 9 07:43:04
2010
@@ -915,18 +915,6 @@
}
break;
}
-
- case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
- CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name,
&miss);
- // Make sure object->HasFastElements().
- // Get the elements array of the object.
- __ ldr(r3, FieldMemOperand(r1, JSObject::kElementsOffset));
- // Check that the object is in fast mode (not dictionary).
- __ ldr(r0, FieldMemOperand(r3, HeapObject::kMapOffset));
- __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
- __ cmp(r0, ip);
- __ b(ne, &miss);
- break;
default:
UNREACHABLE();
=======================================
--- /branches/bleeding_edge/src/bootstrapper.cc Wed Feb 24 11:59:09 2010
+++ /branches/bleeding_edge/src/bootstrapper.cc Tue Mar 9 07:43:04 2010
@@ -245,11 +245,14 @@
bool make_prototype_enumerable = false);
void MakeFunctionInstancePrototypeWritable();
- void AddSpecialFunction(Handle<JSObject> prototype,
- const char* name,
- Handle<Code> code);
-
- void BuildSpecialFunctionTable();
+ Handle<JSFunction> MakeFunctionForBuiltin(Handle<String> name,
+ Handle<Code> code);
+
+ void OverrideWithSpecialFunction(Handle<JSObject> prototype,
+ const char* name,
+ Handle<Code> code);
+
+ void InstallSpecialFunctions();
static bool CompileBuiltin(int index);
static bool CompileNative(Vector<const char> name, Handle<String>
source);
@@ -776,8 +779,6 @@
global_context()->set_call_as_constructor_delegate(*delegate);
delegate->shared()->DontAdaptArguments();
}
-
- global_context()->set_special_function_table(Heap::empty_fixed_array());
// Initialize the out of memory slot.
global_context()->set_out_of_memory(Heap::false_value());
@@ -1457,33 +1458,35 @@
}
-void Genesis::AddSpecialFunction(Handle<JSObject> prototype,
- const char* name,
- Handle<Code> code) {
+Handle<JSFunction> Genesis::MakeFunctionForBuiltin(Handle<String> name,
+ Handle<Code> code) {
+ Handle<JSFunction> optimized = Factory::NewFunction(name,
+ JS_OBJECT_TYPE,
+
JSObject::kHeaderSize,
+ code,
+ false);
+ optimized->shared()->DontAdaptArguments();
+ return optimized;
+}
+
+
+void Genesis::OverrideWithSpecialFunction(Handle<JSObject> prototype,
+ const char* name,
+ Handle<Code> code) {
Handle<String> key = Factory::LookupAsciiSymbol(name);
- Handle<Object> value = Handle<Object>(prototype->GetProperty(*key));
- if (value->IsJSFunction()) {
- Handle<JSFunction> optimized = Factory::NewFunction(key,
- JS_OBJECT_TYPE,
-
JSObject::kHeaderSize,
- code,
- false);
- optimized->shared()->DontAdaptArguments();
- int len = global_context()->special_function_table()->length();
- Handle<FixedArray> new_array = Factory::NewFixedArray(len + 3);
- for (int index = 0; index < len; index++) {
- new_array->set(index,
-
global_context()->special_function_table()->get(index));
- }
- new_array->set(len+0, *prototype);
- new_array->set(len+1, *value);
- new_array->set(len+2, *optimized);
- global_context()->set_special_function_table(*new_array);
- }
+ Handle<Object> old_value = GetProperty(prototype, key);
+ // Check if the function is present in the first place.
+ // For example, FLAG_natives_file could affect if Array functions
+ // are installed at all.
+ if (!old_value->IsJSFunction()) return;
+ int old_length = Handle<JSFunction>::cast(old_value)->shared()->length();
+ Handle<JSFunction> optimized = MakeFunctionForBuiltin(key, code);
+ optimized->shared()->set_length(old_length);
+ SetProperty(prototype, key, optimized, NONE);
}
-void Genesis::BuildSpecialFunctionTable() {
+void Genesis::InstallSpecialFunctions() {
HandleScope scope;
Handle<JSObject> global = Handle<JSObject>(global_context()->global());
// Add special versions for some Array.prototype functions.
@@ -1501,18 +1504,24 @@
} else {
special_prototype = visible_prototype;
}
- AddSpecialFunction(special_prototype, "pop",
- Handle<Code>(Builtins::builtin(Builtins::ArrayPop)));
- AddSpecialFunction(special_prototype, "push",
- Handle<Code>(Builtins::builtin(Builtins::ArrayPush)));
- AddSpecialFunction(special_prototype, "shift",
-
Handle<Code>(Builtins::builtin(Builtins::ArrayShift)));
- AddSpecialFunction(special_prototype, "unshift",
-
Handle<Code>(Builtins::builtin(Builtins::ArrayUnshift)));
- AddSpecialFunction(special_prototype, "slice",
-
Handle<Code>(Builtins::builtin(Builtins::ArraySlice)));
- AddSpecialFunction(special_prototype, "splice",
-
Handle<Code>(Builtins::builtin(Builtins::ArraySplice)));
+ OverrideWithSpecialFunction(
+ special_prototype, "pop",
+ Handle<Code>(Builtins::builtin(Builtins::ArrayPop)));
+ OverrideWithSpecialFunction(
+ special_prototype, "push",
+ Handle<Code>(Builtins::builtin(Builtins::ArrayPush)));
+ OverrideWithSpecialFunction(
+ special_prototype, "shift",
+ Handle<Code>(Builtins::builtin(Builtins::ArrayShift)));
+ OverrideWithSpecialFunction(
+ special_prototype, "unshift",
+ Handle<Code>(Builtins::builtin(Builtins::ArrayUnshift)));
+ OverrideWithSpecialFunction(
+ special_prototype, "slice",
+ Handle<Code>(Builtins::builtin(Builtins::ArraySlice)));
+ OverrideWithSpecialFunction(
+ special_prototype, "splice",
+ Handle<Code>(Builtins::builtin(Builtins::ArraySplice)));
}
@@ -1539,7 +1548,7 @@
if (!InstallNatives()) return;
MakeFunctionInstancePrototypeWritable();
- BuildSpecialFunctionTable();
+ InstallSpecialFunctions();
if (!ConfigureGlobalObjects(global_template)) return;
=======================================
--- /branches/bleeding_edge/src/builtins.cc Fri Mar 5 08:46:39 2010
+++ /branches/bleeding_edge/src/builtins.cc Tue Mar 9 07:43:04 2010
@@ -317,6 +317,24 @@
ASSERT(proto->GetPrototype()->IsNull());
return true;
}
+
+
+static bool IsJSArrayWithFastElements(Object* receiver,
+ FixedArray** elements) {
+ if (!receiver->IsJSArray()) {
+ return false;
+ }
+
+ JSArray* array = JSArray::cast(receiver);
+
+ HeapObject* elms = HeapObject::cast(array->elements());
+ if (elms->map() != Heap::fixed_array_map()) {
+ return false;
+ }
+
+ *elements = FixedArray::cast(elms);
+ return true;
+}
static Object* CallJsBuiltin(const char* name,
@@ -346,8 +364,12 @@
BUILTIN(ArrayPush) {
- JSArray* array = JSArray::cast(*args.receiver());
- ASSERT(array->HasFastElements());
+ Object* receiver = *args.receiver();
+ FixedArray* elms = NULL;
+ if (!IsJSArrayWithFastElements(receiver, &elms)) {
+ return CallJsBuiltin("ArrayPush", args);
+ }
+ JSArray* array = JSArray::cast(receiver);
int len = Smi::cast(array->length())->value();
int to_add = args.length() - 1;
@@ -359,7 +381,6 @@
ASSERT(to_add <= (Smi::kMaxValue - len));
int new_length = len + to_add;
- FixedArray* elms = FixedArray::cast(array->elements());
if (new_length > elms->length()) {
// New backing storage is needed.
@@ -390,14 +411,17 @@
BUILTIN(ArrayPop) {
- JSArray* array = JSArray::cast(*args.receiver());
- ASSERT(array->HasFastElements());
+ Object* receiver = *args.receiver();
+ FixedArray* elms = NULL;
+ if (!IsJSArrayWithFastElements(receiver, &elms)) {
+ return CallJsBuiltin("ArrayPop", args);
+ }
+ JSArray* array = JSArray::cast(receiver);
int len = Smi::cast(array->length())->value();
if (len == 0) return Heap::undefined_value();
// Get top element
- FixedArray* elms = FixedArray::cast(array->elements());
Object* top = elms->get(len - 1);
// Set the length.
@@ -420,18 +444,18 @@
BUILTIN(ArrayShift) {
- if (!ArrayPrototypeHasNoElements()) {
+ Object* receiver = *args.receiver();
+ FixedArray* elms = NULL;
+ if (!IsJSArrayWithFastElements(receiver, &elms)
+ || !ArrayPrototypeHasNoElements()) {
return CallJsBuiltin("ArrayShift", args);
}
-
- JSArray* array = JSArray::cast(*args.receiver());
+ JSArray* array = JSArray::cast(receiver);
ASSERT(array->HasFastElements());
int len = Smi::cast(array->length())->value();
if (len == 0) return Heap::undefined_value();
- FixedArray* elms = FixedArray::cast(array->elements());
-
// Get first element
Object* first = elms->get(0);
if (first->IsTheHole()) {
@@ -451,11 +475,13 @@
BUILTIN(ArrayUnshift) {
- if (!ArrayPrototypeHasNoElements()) {
+ Object* receiver = *args.receiver();
+ FixedArray* elms = NULL;
+ if (!IsJSArrayWithFastElements(receiver, &elms)
+ || !ArrayPrototypeHasNoElements()) {
return CallJsBuiltin("ArrayUnshift", args);
}
-
- JSArray* array = JSArray::cast(*args.receiver());
+ JSArray* array = JSArray::cast(receiver);
ASSERT(array->HasFastElements());
int len = Smi::cast(array->length())->value();
@@ -469,8 +495,6 @@
// we should never hit this case.
ASSERT(to_add <= (Smi::kMaxValue - len));
- FixedArray* elms = FixedArray::cast(array->elements());
-
if (new_length > elms->length()) {
// New backing storage is needed.
int capacity = new_length + (new_length >> 1) + 16;
@@ -503,11 +527,13 @@
BUILTIN(ArraySlice) {
- if (!ArrayPrototypeHasNoElements()) {
+ Object* receiver = *args.receiver();
+ FixedArray* elms = NULL;
+ if (!IsJSArrayWithFastElements(receiver, &elms)
+ || !ArrayPrototypeHasNoElements()) {
return CallJsBuiltin("ArraySlice", args);
}
-
- JSArray* array = JSArray::cast(*args.receiver());
+ JSArray* array = JSArray::cast(receiver);
ASSERT(array->HasFastElements());
int len = Smi::cast(array->length())->value();
@@ -558,8 +584,6 @@
if (result->IsFailure()) return result;
FixedArray* result_elms = FixedArray::cast(result);
- FixedArray* elms = FixedArray::cast(array->elements());
-
AssertNoAllocation no_gc;
CopyElements(&no_gc, result_elms, 0, elms, k, result_len);
@@ -573,11 +597,13 @@
BUILTIN(ArraySplice) {
- if (!ArrayPrototypeHasNoElements()) {
+ Object* receiver = *args.receiver();
+ FixedArray* elms = NULL;
+ if (!IsJSArrayWithFastElements(receiver, &elms)
+ || !ArrayPrototypeHasNoElements()) {
return CallJsBuiltin("ArraySplice", args);
}
-
- JSArray* array = JSArray::cast(*args.receiver());
+ JSArray* array = JSArray::cast(receiver);
ASSERT(array->HasFastElements());
int len = Smi::cast(array->length())->value();
@@ -618,8 +644,6 @@
}
int actual_delete_count = Min(Max(delete_count, 0), len - actual_start);
- FixedArray* elms = FixedArray::cast(array->elements());
-
JSArray* result_array = NULL;
if (actual_delete_count == 0) {
Object* result = AllocateEmptyJSArray();
=======================================
--- /branches/bleeding_edge/src/contexts.h Wed Feb 24 11:59:09 2010
+++ /branches/bleeding_edge/src/contexts.h Tue Mar 9 07:43:04 2010
@@ -50,12 +50,6 @@
// must always be allocated via Heap::AllocateContext() or
// Factory::NewContext.
-// Comment for special_function_table:
-// Table for providing optimized/specialized functions.
-// The array contains triplets [object, general_function,
optimized_function].
-// Primarily added to support built-in optimized variants of
-// Array.prototype.{push,pop}.
-
#define GLOBAL_CONTEXT_FIELDS(V) \
V(GLOBAL_PROXY_INDEX, JSObject, global_proxy_object) \
V(SECURITY_TOKEN_INDEX, Object, security_token) \
@@ -82,7 +76,6 @@
V(FUNCTION_MAP_INDEX, Map, function_map) \
V(FUNCTION_INSTANCE_MAP_INDEX, Map, function_instance_map) \
V(JS_ARRAY_MAP_INDEX, Map, js_array_map)\
- V(SPECIAL_FUNCTION_TABLE_INDEX, FixedArray, special_function_table) \
V(ARGUMENTS_BOILERPLATE_INDEX, JSObject, arguments_boilerplate) \
V(MESSAGE_LISTENERS_INDEX, JSObject, message_listeners) \
V(MAKE_MESSAGE_FUN_INDEX, JSFunction, make_message_fun) \
@@ -206,7 +199,6 @@
GLOBAL_EVAL_FUN_INDEX,
INSTANTIATE_FUN_INDEX,
CONFIGURE_INSTANCE_FUN_INDEX,
- SPECIAL_FUNCTION_TABLE_INDEX,
MESSAGE_LISTENERS_INDEX,
MAKE_MESSAGE_FUN_INDEX,
GET_STACK_TRACE_LINE_INDEX,
=======================================
--- /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Thu Feb 25 10:04:25
2010
+++ /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Tue Mar 9 07:43:04
2010
@@ -698,8 +698,7 @@
CallOptimization optimization(lookup);
- if (optimization.is_constant_call() &&
- !Top::CanHaveSpecialFunctions(holder)) {
+ if (optimization.is_constant_call()) {
CompileCacheable(masm,
object,
receiver,
@@ -1332,18 +1331,6 @@
}
break;
}
-
- case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
- CheckPrototypes(JSObject::cast(object), edx, holder,
- ebx, eax, name, &miss);
- // Make sure object->HasFastElements().
- // Get the elements array of the object.
- __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
- // Check that the object is in fast mode (not dictionary).
- __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
- Immediate(Factory::fixed_array_map()));
- __ j(not_equal, &miss, not_taken);
- break;
default:
UNREACHABLE();
=======================================
--- /branches/bleeding_edge/src/ic.cc Tue Mar 9 02:49:41 2010
+++ /branches/bleeding_edge/src/ic.cc Tue Mar 9 07:43:04 2010
@@ -458,17 +458,6 @@
ASSERT(result != Heap::the_hole_value());
if (result->IsJSFunction()) {
- // Check if there is an optimized (builtin) version of the function.
- // Ignored this will degrade performance for some Array functions.
- // Please note we only return the optimized function iff
- // the JSObject has FastElements.
- if (object->IsJSObject() &&
JSObject::cast(*object)->HasFastElements()) {
- Object* opt = Top::LookupSpecialFunction(JSObject::cast(*object),
- lookup.holder(),
- JSFunction::cast(result));
- if (opt->IsJSFunction()) return opt;
- }
-
#ifdef ENABLE_DEBUGGER_SUPPORT
// Handle stepping into a function if step into is active.
if (Debug::StepInActive()) {
=======================================
--- /branches/bleeding_edge/src/stub-cache.cc Mon Feb 22 02:04:22 2010
+++ /branches/bleeding_edge/src/stub-cache.cc Tue Mar 9 07:43:04 2010
@@ -435,14 +435,6 @@
argc);
Object* code = map->FindInCodeCache(name, flags);
if (code->IsUndefined()) {
- if (object->IsJSObject()) {
- Object* opt =
- Top::LookupSpecialFunction(JSObject::cast(object), holder,
function);
- if (opt->IsJSFunction()) {
- check = StubCompiler::JSARRAY_HAS_FAST_ELEMENTS_CHECK;
- function = JSFunction::cast(opt);
- }
- }
// If the function hasn't been compiled yet, we cannot do it now
// because it may cause GC. To avoid this issue, we return an
// internal error which will make sure we do not update any
=======================================
--- /branches/bleeding_edge/src/stub-cache.h Mon Feb 15 05:20:49 2010
+++ /branches/bleeding_edge/src/stub-cache.h Tue Mar 9 07:43:04 2010
@@ -326,8 +326,7 @@
RECEIVER_MAP_CHECK,
STRING_CHECK,
NUMBER_CHECK,
- BOOLEAN_CHECK,
- JSARRAY_HAS_FAST_ELEMENTS_CHECK
+ BOOLEAN_CHECK
};
StubCompiler() : scope_(), masm_(NULL, 256), failure_(NULL) { }
=======================================
--- /branches/bleeding_edge/src/top.cc Mon Mar 8 22:38:33 2010
+++ /branches/bleeding_edge/src/top.cc Tue Mar 9 07:43:04 2010
@@ -948,27 +948,6 @@
Context* context = Context::cast(frame->context());
return Handle<Context>(context->global_context());
}
-
-
-bool Top::CanHaveSpecialFunctions(JSObject* object) {
- return object->IsJSArray();
-}
-
-
-Object* Top::LookupSpecialFunction(JSObject* receiver,
- JSObject* prototype,
- JSFunction* function) {
- if (CanHaveSpecialFunctions(receiver)) {
- FixedArray* table =
context()->global_context()->special_function_table();
- for (int index = 0; index < table->length(); index +=3) {
- if ((prototype == table->get(index)) &&
- (function == table->get(index+1))) {
- return table->get(index+2);
- }
- }
- }
- return Heap::undefined_value();
-}
char* Top::ArchiveThread(char* to) {
=======================================
--- /branches/bleeding_edge/src/top.h Tue Feb 9 08:14:14 2010
+++ /branches/bleeding_edge/src/top.h Tue Mar 9 07:43:04 2010
@@ -341,11 +341,6 @@
static Handle<JSBuiltinsObject> builtins() {
return Handle<JSBuiltinsObject>(thread_local_.context_->builtins());
}
-
- static bool CanHaveSpecialFunctions(JSObject* object);
- static Object* LookupSpecialFunction(JSObject* receiver,
- JSObject* prototype,
- JSFunction* value);
static void RegisterTryCatchHandler(v8::TryCatch* that);
static void UnregisterTryCatchHandler(v8::TryCatch* that);
=======================================
--- /branches/bleeding_edge/src/x64/stub-cache-x64.cc Wed Feb 24 00:33:51
2010
+++ /branches/bleeding_edge/src/x64/stub-cache-x64.cc Tue Mar 9 07:43:04
2010
@@ -758,18 +758,6 @@
}
break;
}
-
- case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
- CheckPrototypes(JSObject::cast(object), rdx, holder,
- rbx, rax, name, &miss);
- // Make sure object->HasFastElements().
- // Get the elements array of the object.
- __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
- // Check that the object is in fast mode (not dictionary).
- __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset),
- Factory::fixed_array_map());
- __ j(not_equal, &miss);
- break;
default:
UNREACHABLE();
=======================================
--- /branches/bleeding_edge/test/cctest/test-serialize.cc Thu Mar 4
06:45:36 2010
+++ /branches/bleeding_edge/test/cctest/test-serialize.cc Tue Mar 9
07:43:04 2010
@@ -283,7 +283,6 @@
#endif
CHECK(Top::global()->IsJSObject());
CHECK(Top::global_context()->IsContext());
- CHECK(Top::special_function_table()->IsFixedArray());
CHECK(Heap::symbol_table()->IsSymbolTable());
CHECK(!Factory::LookupAsciiSymbol("Empty")->IsFailure());
}
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev