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:
parent
1273621943
commit
ee1dc27795
@ -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
|
||||
|
@ -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 =
|
||||
|
@ -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
|
||||
|
@ -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?
|
||||
¬_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(¬_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));
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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) \
|
||||
|
@ -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. */ \
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user