Index: src/ia32/builtins-ia32.cc |
diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc |
index 1c2eb94cf583a3a236c829a982a32c2143276bc3..b133290b4d07488655d70ceb5bbd3bca60943610 100644 |
--- a/src/ia32/builtins-ia32.cc |
+++ b/src/ia32/builtins-ia32.cc |
@@ -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 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); |
antonm
2010/08/26 13:51:16
maybe add a check under FLAG_debug_code above this
|
+ 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)); |