Fast string construct stub (ia32 only for now).

Review URL: http://codereview.chromium.org/3211002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5357 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
vitalyr@chromium.org 2010-08-26 13:59:37 +00:00
parent 1273621943
commit ee1dc27795
11 changed files with 197 additions and 24 deletions

View File

@ -481,6 +481,13 @@ void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
}
void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
// TODO(849): implement custom construct stub.
// Generate a copy of the generic stub for now.
Generate_JSConstructStubGeneric(masm);
}
void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : number of arguments

View File

@ -720,6 +720,8 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
InstallFunction(global, "String", JS_VALUE_TYPE, JSValue::kSize,
Top::initial_object_prototype(), Builtins::Illegal,
true);
string_fun->shared()->set_construct_stub(
Builtins::builtin(Builtins::StringConstructCode));
global_context()->set_string_function(*string_fun);
// Add 'length' property to strings.
Handle<DescriptorArray> string_descriptors =

View File

@ -117,7 +117,10 @@ enum BuiltinExtraArguments {
V(FunctionApply, BUILTIN, UNINITIALIZED) \
\
V(ArrayCode, BUILTIN, UNINITIALIZED) \
V(ArrayConstructCode, BUILTIN, UNINITIALIZED)
V(ArrayConstructCode, BUILTIN, UNINITIALIZED) \
\
V(StringConstructCode, BUILTIN, UNINITIALIZED)
#ifdef ENABLE_DEBUGGER_SUPPORT
// Define list of builtins used by the debugger implemented in assembly.
@ -258,6 +261,8 @@ class Builtins : public AllStatic {
static void Generate_ArrayCode(MacroAssembler* masm);
static void Generate_ArrayConstructCode(MacroAssembler* masm);
static void Generate_StringConstructCode(MacroAssembler* masm);
};
} } // namespace v8::internal

View File

@ -29,6 +29,7 @@
#if defined(V8_TARGET_ARCH_IA32)
#include "code-stubs-ia32.h"
#include "codegen-inl.h"
namespace v8 {
@ -695,17 +696,6 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
}
// Load the built-in Array function from the current context.
static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) {
// Load the global context.
__ mov(result, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
__ mov(result, FieldOperand(result, GlobalObject::kGlobalContextOffset));
// Load the Array function from the global context.
__ mov(result,
Operand(result, Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
}
// Number of empty elements to allocate for an empty array.
static const int kPreallocatedArrayElements = 4;
@ -1095,7 +1085,7 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
Label generic_array_code;
// Get the Array function.
GenerateLoadArrayFunction(masm, edi);
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi);
if (FLAG_debug_code) {
// Initial map for the builtin Array function shoud be a map.
@ -1131,7 +1121,7 @@ void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
if (FLAG_debug_code) {
// The array construct code is only set for the builtin Array function which
// does always have a map.
GenerateLoadArrayFunction(masm, ebx);
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, ebx);
__ cmp(edi, Operand(ebx));
__ Assert(equal, "Unexpected Array function");
// Initial map for the builtin Array function should be a map.
@ -1155,6 +1145,131 @@ void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
}
void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : number of arguments
// -- edi : constructor function
// -- esp[0] : return address
// -- esp[(argc - n) * 4] : arg[n] (zero-based)
// -- esp[(argc + 1) * 4] : receiver
// -----------------------------------
__ IncrementCounter(&Counters::string_ctor_calls, 1);
if (FLAG_debug_code) {
__ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, ecx);
__ cmp(edi, Operand(ecx));
__ Assert(equal, "Unexpected String function");
}
// Load the first argument into eax and get rid of the rest
// (including the receiver).
Label no_arguments;
__ test(eax, Operand(eax));
__ j(zero, &no_arguments);
__ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
__ pop(ecx);
__ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
__ push(ecx);
__ mov(eax, ebx);
// Lookup the argument in the number to string cache.
Label not_cached, argument_is_string;
NumberToStringStub::GenerateLookupNumberStringCache(
masm,
eax, // Input.
ebx, // Result.
ecx, // Scratch 1.
edx, // Scratch 2.
false, // Input is known to be smi?
&not_cached);
__ IncrementCounter(&Counters::string_ctor_cached_number, 1);
__ bind(&argument_is_string);
// ----------- S t a t e -------------
// -- ebx : argument converted to string
// -- edi : constructor function
// -- esp[0] : return address
// -----------------------------------
// Allocate a JSValue and put the tagged pointer into eax.
Label gc_required;
__ AllocateInNewSpace(JSValue::kSize,
eax, // Result.
ecx, // New allocation top (we ignore it).
no_reg,
&gc_required,
TAG_OBJECT);
// Set the map.
__ LoadGlobalFunctionInitialMap(edi, ecx);
if (FLAG_debug_code) {
__ cmpb(FieldOperand(ecx, Map::kInstanceSizeOffset),
JSValue::kSize >> kPointerSizeLog2);
__ Assert(equal, "Unexpected string wrapper instance size");
__ cmpb(FieldOperand(ecx, Map::kUnusedPropertyFieldsOffset), 0);
__ Assert(equal, "Unexpected unused properties of string wrapper");
}
__ mov(FieldOperand(eax, HeapObject::kMapOffset), ecx);
// Set properties and elements.
__ Set(ecx, Immediate(Factory::empty_fixed_array()));
__ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx);
__ mov(FieldOperand(eax, JSObject::kElementsOffset), ecx);
// Set the value.
__ mov(FieldOperand(eax, JSValue::kValueOffset), ebx);
// Ensure the object is fully initialized.
STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
// We're done. Return.
__ ret(0);
// The argument was not found in the number to string cache. Check
// if it's a string already before calling the conversion builtin.
Label convert_argument;
__ bind(&not_cached);
STATIC_ASSERT(kSmiTag == 0);
__ test(eax, Immediate(kSmiTagMask));
__ j(zero, &convert_argument);
Condition is_string = masm->IsObjectStringType(eax, ebx, ecx);
__ j(NegateCondition(is_string), &convert_argument);
__ mov(ebx, eax);
__ IncrementCounter(&Counters::string_ctor_string_value, 1);
__ jmp(&argument_is_string);
// Invoke the conversion builtin and put the result into ebx.
__ bind(&convert_argument);
__ IncrementCounter(&Counters::string_ctor_conversions, 1);
__ EnterInternalFrame();
__ push(edi); // Preserve the function.
__ push(eax);
__ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION);
__ pop(edi);
__ LeaveInternalFrame();
__ mov(ebx, eax);
__ jmp(&argument_is_string);
// Load the empty string into ebx, remove the receiver from the
// stack, and jump back to the case where the argument is a string.
__ bind(&no_arguments);
__ Set(ebx, Immediate(Factory::empty_string()));
__ pop(ecx);
__ lea(esp, Operand(esp, kPointerSize));
__ push(ecx);
__ jmp(&argument_is_string);
// At this point the argument is already a string. Call runtime to
// create a string wrapper.
__ bind(&gc_required);
__ IncrementCounter(&Counters::string_ctor_gc_required, 1);
__ EnterInternalFrame();
__ push(ebx);
__ CallRuntime(Runtime::kNewStringWrapper, 1);
__ LeaveInternalFrame();
__ ret(0);
}
static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
__ push(ebp);
__ mov(ebp, Operand(esp));

View File

@ -1369,6 +1369,30 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
}
void MacroAssembler::LoadGlobalFunction(int index, Register function) {
// Load the global or builtins object from the current context.
mov(function, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
// Load the global context from the global or builtins object.
mov(function, FieldOperand(function, GlobalObject::kGlobalContextOffset));
// Load the function from the global context.
mov(function, Operand(function, Context::SlotOffset(index)));
}
void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
Register map) {
// Load the initial map. The global functions all have initial maps.
mov(map, FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
if (FLAG_debug_code) {
Label ok, fail;
CheckMap(map, Factory::meta_map(), &fail, false);
jmp(&ok);
bind(&fail);
Abort("Global functions must have initial map");
bind(&ok);
}
}
void MacroAssembler::Ret() {
ret(0);

View File

@ -140,6 +140,13 @@ class MacroAssembler: public Assembler {
// Find the function context up the context chain.
void LoadContext(Register dst, int context_chain_length);
// Load the global function with the given index.
void LoadGlobalFunction(int index, Register function);
// Load the initial map from the global function. The registers
// function and map can be the same.
void LoadGlobalFunctionInitialMap(Register function, Register map);
// ---------------------------------------------------------------------------
// JavaScript invokes

View File

@ -257,16 +257,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
int index,
Register prototype) {
// Load the global or builtins object from the current context.
__ mov(prototype, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
// Load the global context from the global or builtins object.
__ mov(prototype,
FieldOperand(prototype, GlobalObject::kGlobalContextOffset));
// Load the function from the global context.
__ mov(prototype, Operand(prototype, Context::SlotOffset(index)));
// Load the initial map. The global functions all have initial maps.
__ mov(prototype,
FieldOperand(prototype, JSFunction::kPrototypeOrInitialMapOffset));
__ LoadGlobalFunction(index, prototype);
__ LoadGlobalFunctionInitialMap(prototype, prototype);
// Load the prototype from the initial map.
__ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
}

View File

@ -5575,6 +5575,14 @@ static Object* Runtime_StringToArray(Arguments args) {
}
static Object* Runtime_NewStringWrapper(Arguments args) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);
CONVERT_CHECKED(String, value, args[0]);
return value->ToObject();
}
bool Runtime::IsUpperCaseChar(uint16_t ch) {
unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
int char_length = to_upper_mapping.get(ch, 0, chars);

View File

@ -174,6 +174,7 @@ namespace internal {
F(StringMatch, 3, 1) \
F(StringTrim, 3, 1) \
F(StringToArray, 1, 1) \
F(NewStringWrapper, 1, 1) \
\
/* Numbers */ \
F(NumberToRadixString, 2, 1) \

View File

@ -85,6 +85,11 @@ namespace internal {
SC(compilation_cache_misses, V8.CompilationCacheMisses) \
SC(regexp_cache_hits, V8.RegExpCacheHits) \
SC(regexp_cache_misses, V8.RegExpCacheMisses) \
SC(string_ctor_calls, V8.StringConstructorCalls) \
SC(string_ctor_conversions, V8.StringConstructorConversions) \
SC(string_ctor_cached_number, V8.StringConstructorCachedNumber) \
SC(string_ctor_string_value, V8.StringConstructorStringValue) \
SC(string_ctor_gc_required, V8.StringConstructorGCRequired) \
/* Amount of evaled source code. */ \
SC(total_eval_size, V8.TotalEvalSize) \
/* Amount of loaded source code. */ \

View File

@ -875,6 +875,13 @@ void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
}
void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
// TODO(849): implement custom construct stub.
// Generate a copy of the generic stub for now.
Generate_JSConstructStubGeneric(masm);
}
void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax: number of arguments