Revision: 5357
Author: [email protected]
Date: Thu Aug 26 06:59:37 2010
Log: Fast string construct stub (ia32 only for now).
Review URL: http://codereview.chromium.org/3211002
http://code.google.com/p/v8/source/detail?r=5357
Modified:
/branches/bleeding_edge/src/arm/builtins-arm.cc
/branches/bleeding_edge/src/bootstrapper.cc
/branches/bleeding_edge/src/builtins.h
/branches/bleeding_edge/src/ia32/builtins-ia32.cc
/branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc
/branches/bleeding_edge/src/ia32/macro-assembler-ia32.h
/branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
/branches/bleeding_edge/src/runtime.cc
/branches/bleeding_edge/src/runtime.h
/branches/bleeding_edge/src/v8-counters.h
/branches/bleeding_edge/src/x64/builtins-x64.cc
=======================================
--- /branches/bleeding_edge/src/arm/builtins-arm.cc Wed Aug 25 00:18:32 2010
+++ /branches/bleeding_edge/src/arm/builtins-arm.cc Thu Aug 26 06:59:37 2010
@@ -479,6 +479,13 @@
Handle<Code> generic_construct_stub(code);
__ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
}
+
+
+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) {
=======================================
--- /branches/bleeding_edge/src/bootstrapper.cc Wed Aug 25 06:25:54 2010
+++ /branches/bleeding_edge/src/bootstrapper.cc Thu Aug 26 06:59:37 2010
@@ -720,6 +720,8 @@
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 =
=======================================
--- /branches/bleeding_edge/src/builtins.h Wed Aug 11 06:48:58 2010
+++ /branches/bleeding_edge/src/builtins.h Thu Aug 26 06:59:37 2010
@@ -117,7 +117,10 @@
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 @@
static void Generate_ArrayCode(MacroAssembler* masm);
static void Generate_ArrayConstructCode(MacroAssembler* masm);
+
+ static void Generate_StringConstructCode(MacroAssembler* masm);
};
} } // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/ia32/builtins-ia32.cc Wed Aug 25 00:18:32
2010
+++ /branches/bleeding_edge/src/ia32/builtins-ia32.cc Thu Aug 26 06:59:37
2010
@@ -29,6 +29,7 @@
#if defined(V8_TARGET_ARCH_IA32)
+#include "code-stubs-ia32.h"
#include "codegen-inl.h"
namespace v8 {
@@ -693,17 +694,6 @@
__ LeaveInternalFrame();
__ ret(3 * kPointerSize); // remove this, receiver, and arguments
}
-
-
-// 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.
@@ -1095,7 +1085,7 @@
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 @@
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.
@@ -1153,6 +1143,131 @@
Handle<Code> generic_construct_stub(code);
__ jmp(generic_construct_stub, RelocInfo::CODE_TARGET);
}
+
+
+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) {
=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Fri Aug 20
00:10:18 2010
+++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Thu Aug 26
06:59:37 2010
@@ -1369,6 +1369,30 @@
}
+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);
=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Fri Aug 20
00:10:18 2010
+++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Thu Aug 26
06:59:37 2010
@@ -140,6 +140,13 @@
// 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
=======================================
--- /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Mon Aug 16 09:06:46
2010
+++ /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Thu Aug 26 06:59:37
2010
@@ -257,16 +257,8 @@
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));
}
=======================================
--- /branches/bleeding_edge/src/runtime.cc Wed Aug 25 10:50:37 2010
+++ /branches/bleeding_edge/src/runtime.cc Thu Aug 26 06:59:37 2010
@@ -5573,6 +5573,14 @@
return *Factory::NewJSArrayWithElements(elements);
}
+
+
+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) {
=======================================
--- /branches/bleeding_edge/src/runtime.h Wed Aug 25 10:50:37 2010
+++ /branches/bleeding_edge/src/runtime.h Thu Aug 26 06:59:37 2010
@@ -174,6 +174,7 @@
F(StringMatch, 3, 1) \
F(StringTrim, 3, 1) \
F(StringToArray, 1, 1) \
+ F(NewStringWrapper, 1, 1) \
\
/* Numbers */ \
F(NumberToRadixString, 2, 1) \
=======================================
--- /branches/bleeding_edge/src/v8-counters.h Wed Aug 25 06:25:54 2010
+++ /branches/bleeding_edge/src/v8-counters.h Thu Aug 26 06:59:37 2010
@@ -85,6 +85,11 @@
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. */ \
=======================================
--- /branches/bleeding_edge/src/x64/builtins-x64.cc Wed Aug 25 00:18:32 2010
+++ /branches/bleeding_edge/src/x64/builtins-x64.cc Thu Aug 26 06:59:37 2010
@@ -873,6 +873,13 @@
Handle<Code> generic_construct_stub(code);
__ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
}
+
+
+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) {
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev