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();
}
bool make_prototype_enumerable = false);
void MakeFunctionInstancePrototypeWritable();
- void AddSpecialFunction(Handle<JSObject> prototype,
- const char* name,
- Handle<Code> code);
+ Handle<JSFunction> MakeFunctionForBuiltin(Handle<String> name,
+ Handle<Code> code);
- void BuildSpecialFunctionTable();
+ 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);
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());
}
-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.
} 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)));
}
if (!InstallNatives()) return;
MakeFunctionInstancePrototypeWritable();
- BuildSpecialFunctionTable();
+ InstallSpecialFunctions();
if (!ConfigureGlobalObjects(global_template)) return;
}
+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,
BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
HandleScope handleScope;
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;
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.
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.
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()) {
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();
// 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;
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();
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);
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();
}
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();
// 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) \
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) \
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,
CallOptimization optimization(lookup);
- if (optimization.is_constant_call() &&
- !Top::CanHaveSpecialFunctions(holder)) {
+ if (optimization.is_constant_call()) {
CompileCacheable(masm,
object,
receiver,
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();
}
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()) {
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
RECEIVER_MAP_CHECK,
STRING_CHECK,
NUMBER_CHECK,
- BOOLEAN_CHECK,
- JSARRAY_HAS_FAST_ELEMENTS_CHECK
+ BOOLEAN_CHECK
};
StubCompiler() : scope_(), masm_(NULL, 256), failure_(NULL) { }
}
-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) {
memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(thread_local_));
InitializeThreadLocal();
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);
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();
}
#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());
}