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) {
|
void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
// -- r0 : number of arguments
|
// -- r0 : number of arguments
|
||||||
|
@ -720,6 +720,8 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
|
|||||||
InstallFunction(global, "String", JS_VALUE_TYPE, JSValue::kSize,
|
InstallFunction(global, "String", JS_VALUE_TYPE, JSValue::kSize,
|
||||||
Top::initial_object_prototype(), Builtins::Illegal,
|
Top::initial_object_prototype(), Builtins::Illegal,
|
||||||
true);
|
true);
|
||||||
|
string_fun->shared()->set_construct_stub(
|
||||||
|
Builtins::builtin(Builtins::StringConstructCode));
|
||||||
global_context()->set_string_function(*string_fun);
|
global_context()->set_string_function(*string_fun);
|
||||||
// Add 'length' property to strings.
|
// Add 'length' property to strings.
|
||||||
Handle<DescriptorArray> string_descriptors =
|
Handle<DescriptorArray> string_descriptors =
|
||||||
|
@ -117,7 +117,10 @@ enum BuiltinExtraArguments {
|
|||||||
V(FunctionApply, BUILTIN, UNINITIALIZED) \
|
V(FunctionApply, BUILTIN, UNINITIALIZED) \
|
||||||
\
|
\
|
||||||
V(ArrayCode, BUILTIN, UNINITIALIZED) \
|
V(ArrayCode, BUILTIN, UNINITIALIZED) \
|
||||||
V(ArrayConstructCode, BUILTIN, UNINITIALIZED)
|
V(ArrayConstructCode, BUILTIN, UNINITIALIZED) \
|
||||||
|
\
|
||||||
|
V(StringConstructCode, BUILTIN, UNINITIALIZED)
|
||||||
|
|
||||||
|
|
||||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||||
// Define list of builtins used by the debugger implemented in assembly.
|
// 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_ArrayCode(MacroAssembler* masm);
|
||||||
static void Generate_ArrayConstructCode(MacroAssembler* masm);
|
static void Generate_ArrayConstructCode(MacroAssembler* masm);
|
||||||
|
|
||||||
|
static void Generate_StringConstructCode(MacroAssembler* masm);
|
||||||
};
|
};
|
||||||
|
|
||||||
} } // namespace v8::internal
|
} } // namespace v8::internal
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
#if defined(V8_TARGET_ARCH_IA32)
|
#if defined(V8_TARGET_ARCH_IA32)
|
||||||
|
|
||||||
|
#include "code-stubs-ia32.h"
|
||||||
#include "codegen-inl.h"
|
#include "codegen-inl.h"
|
||||||
|
|
||||||
namespace v8 {
|
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.
|
// Number of empty elements to allocate for an empty array.
|
||||||
static const int kPreallocatedArrayElements = 4;
|
static const int kPreallocatedArrayElements = 4;
|
||||||
|
|
||||||
@ -1095,7 +1085,7 @@ void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
|
|||||||
Label generic_array_code;
|
Label generic_array_code;
|
||||||
|
|
||||||
// Get the Array function.
|
// Get the Array function.
|
||||||
GenerateLoadArrayFunction(masm, edi);
|
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi);
|
||||||
|
|
||||||
if (FLAG_debug_code) {
|
if (FLAG_debug_code) {
|
||||||
// Initial map for the builtin Array function shoud be a map.
|
// 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) {
|
if (FLAG_debug_code) {
|
||||||
// The array construct code is only set for the builtin Array function which
|
// The array construct code is only set for the builtin Array function which
|
||||||
// does always have a map.
|
// does always have a map.
|
||||||
GenerateLoadArrayFunction(masm, ebx);
|
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, ebx);
|
||||||
__ cmp(edi, Operand(ebx));
|
__ cmp(edi, Operand(ebx));
|
||||||
__ Assert(equal, "Unexpected Array function");
|
__ Assert(equal, "Unexpected Array function");
|
||||||
// Initial map for the builtin Array function should be a map.
|
// 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) {
|
static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
|
||||||
__ push(ebp);
|
__ push(ebp);
|
||||||
__ mov(ebp, Operand(esp));
|
__ 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() {
|
void MacroAssembler::Ret() {
|
||||||
ret(0);
|
ret(0);
|
||||||
|
@ -140,6 +140,13 @@ class MacroAssembler: public Assembler {
|
|||||||
// Find the function context up the context chain.
|
// Find the function context up the context chain.
|
||||||
void LoadContext(Register dst, int context_chain_length);
|
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
|
// JavaScript invokes
|
||||||
|
|
||||||
|
@ -257,16 +257,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
|
|||||||
void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
|
void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
|
||||||
int index,
|
int index,
|
||||||
Register prototype) {
|
Register prototype) {
|
||||||
// Load the global or builtins object from the current context.
|
__ LoadGlobalFunction(index, prototype);
|
||||||
__ mov(prototype, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
|
__ LoadGlobalFunctionInitialMap(prototype, prototype);
|
||||||
// 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));
|
|
||||||
// Load the prototype from the initial map.
|
// Load the prototype from the initial map.
|
||||||
__ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset));
|
__ 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) {
|
bool Runtime::IsUpperCaseChar(uint16_t ch) {
|
||||||
unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
|
unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
|
||||||
int char_length = to_upper_mapping.get(ch, 0, chars);
|
int char_length = to_upper_mapping.get(ch, 0, chars);
|
||||||
|
@ -174,6 +174,7 @@ namespace internal {
|
|||||||
F(StringMatch, 3, 1) \
|
F(StringMatch, 3, 1) \
|
||||||
F(StringTrim, 3, 1) \
|
F(StringTrim, 3, 1) \
|
||||||
F(StringToArray, 1, 1) \
|
F(StringToArray, 1, 1) \
|
||||||
|
F(NewStringWrapper, 1, 1) \
|
||||||
\
|
\
|
||||||
/* Numbers */ \
|
/* Numbers */ \
|
||||||
F(NumberToRadixString, 2, 1) \
|
F(NumberToRadixString, 2, 1) \
|
||||||
|
@ -85,6 +85,11 @@ namespace internal {
|
|||||||
SC(compilation_cache_misses, V8.CompilationCacheMisses) \
|
SC(compilation_cache_misses, V8.CompilationCacheMisses) \
|
||||||
SC(regexp_cache_hits, V8.RegExpCacheHits) \
|
SC(regexp_cache_hits, V8.RegExpCacheHits) \
|
||||||
SC(regexp_cache_misses, V8.RegExpCacheMisses) \
|
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. */ \
|
/* Amount of evaled source code. */ \
|
||||||
SC(total_eval_size, V8.TotalEvalSize) \
|
SC(total_eval_size, V8.TotalEvalSize) \
|
||||||
/* Amount of loaded source code. */ \
|
/* 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) {
|
void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
// -- rax: number of arguments
|
// -- rax: number of arguments
|
||||||
|
Loading…
Reference in New Issue
Block a user