Commit 353db409 authored by chunyang.dai's avatar chunyang.dai Committed by Commit bot

X87: [builtins] Simplify String constructor code.

port eadfd666 (r30706).

original commit message:

    The String constructor was somewhat complex with a lot of micro
    optimizations that are not relevant or even misguided. It would be
    really hard to port that code to ES6, which requires String to be
    subclassable. So as a first step we reduced the necessary complexity
    to the bare minimum (also removing the last user of the fairly complex
    MacroAssembler::LookupNumberStringCache method).

    This also removes the counters for the String constructor, which
    were not properly exposed anymore (and not kept in sync with inlined
    versions of the String constructor anyway).

BUG=

Review URL: https://codereview.chromium.org/1336133003

Cr-Commit-Position: refs/heads/master@{#30744}
parent 8c8c7523
......@@ -1259,120 +1259,77 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
// -- esp[(argc - n) * 4] : arg[n] (zero-based)
// -- esp[(argc + 1) * 4] : receiver
// -----------------------------------
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->string_ctor_calls(), 1);
if (FLAG_debug_code) {
__ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, ecx);
__ cmp(edi, ecx);
__ Assert(equal, kUnexpectedStringFunction);
}
// Load the first argument into eax and get rid of the rest
// (including the receiver).
Label no_arguments;
__ test(eax, 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;
__ LookupNumberStringCache(eax, // Input.
ebx, // Result.
ecx, // Scratch 1.
edx, // Scratch 2.
&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;
__ Allocate(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, kUnexpectedStringWrapperInstanceSize);
__ cmpb(FieldOperand(ecx, Map::kUnusedPropertyFieldsOffset), 0);
__ Assert(equal, kUnexpectedUnusedPropertiesOfStringWrapper);
// 1. Load the first argument into ebx and get rid of the rest (including the
// receiver).
{
Label no_arguments, done;
__ test(eax, eax);
__ j(zero, &no_arguments, Label::kNear);
__ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
__ jmp(&done, Label::kNear);
__ bind(&no_arguments);
__ LoadRoot(ebx, Heap::kempty_stringRootIndex);
__ bind(&done);
__ PopReturnAddressTo(ecx);
__ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize));
__ PushReturnAddressFrom(ecx);
}
__ mov(FieldOperand(eax, HeapObject::kMapOffset), ecx);
// Set properties and elements.
Factory* factory = masm->isolate()->factory();
__ Move(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);
__ JumpIfSmi(eax, &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);
// 2. Make sure ebx is a string.
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ push(edi); // Preserve the function.
ToStringStub stub(masm->isolate());
__ CallStub(&stub);
__ pop(edi);
Label convert, done_convert;
__ JumpIfSmi(ebx, &convert, Label::kNear);
__ CmpObjectType(ebx, FIRST_NONSTRING_TYPE, edx);
__ j(below, &done_convert);
__ bind(&convert);
{
FrameScope scope(masm, StackFrame::INTERNAL);
ToStringStub stub(masm->isolate());
__ Push(edi);
__ Move(eax, ebx);
__ CallStub(&stub);
__ Move(ebx, eax);
__ Pop(edi);
}
__ bind(&done_convert);
}
__ 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);
__ Move(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);
// 3. Allocate a JSValue wrapper for the string.
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ push(ebx);
__ CallRuntime(Runtime::kNewStringWrapper, 1);
// ----------- S t a t e -------------
// -- ebx : the first argument
// -- edi : constructor function
// -----------------------------------
Label allocate, done_allocate;
__ Allocate(JSValue::kSize, eax, ecx, no_reg, &allocate, TAG_OBJECT);
__ bind(&done_allocate);
// Initialize the JSValue in eax.
__ LoadGlobalFunctionInitialMap(edi, ecx);
__ mov(FieldOperand(eax, HeapObject::kMapOffset), ecx);
__ mov(FieldOperand(eax, JSObject::kPropertiesOffset),
masm->isolate()->factory()->empty_fixed_array());
__ mov(FieldOperand(eax, JSObject::kElementsOffset),
masm->isolate()->factory()->empty_fixed_array());
__ mov(FieldOperand(eax, JSValue::kValueOffset), ebx);
STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
__ Ret();
// Fallback to the runtime to allocate in new space.
__ bind(&allocate);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(ebx);
__ Push(edi);
__ Push(Smi::FromInt(JSValue::kSize));
__ CallRuntime(Runtime::kAllocateInNewSpace, 1);
__ Pop(edi);
__ Pop(ebx);
}
__ jmp(&done_allocate);
}
__ ret(0);
}
......
......@@ -2470,82 +2470,6 @@ void MacroAssembler::LoadAccessor(Register dst, Register holder,
}
void MacroAssembler::LookupNumberStringCache(Register object,
Register result,
Register scratch1,
Register scratch2,
Label* not_found) {
// Use of registers. Register result is used as a temporary.
Register number_string_cache = result;
Register mask = scratch1;
Register scratch = scratch2;
// Load the number string cache.
LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex);
// Make the hash mask from the length of the number string cache. It
// contains two elements (number and string) for each cache entry.
mov(mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset));
shr(mask, kSmiTagSize + 1); // Untag length and divide it by two.
sub(mask, Immediate(1)); // Make mask.
// Calculate the entry in the number string cache. The hash value in the
// number string cache for smis is just the smi value, and the hash for
// doubles is the xor of the upper and lower words. See
// Heap::GetNumberStringCache.
Label smi_hash_calculated;
Label load_result_from_cache;
Label not_smi;
STATIC_ASSERT(kSmiTag == 0);
JumpIfNotSmi(object, &not_smi, Label::kNear);
mov(scratch, object);
SmiUntag(scratch);
jmp(&smi_hash_calculated, Label::kNear);
bind(&not_smi);
cmp(FieldOperand(object, HeapObject::kMapOffset),
isolate()->factory()->heap_number_map());
j(not_equal, not_found);
STATIC_ASSERT(8 == kDoubleSize);
mov(scratch, FieldOperand(object, HeapNumber::kValueOffset));
xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4));
// Object is heap number and hash is now in scratch. Calculate cache index.
and_(scratch, mask);
Register index = scratch;
Register probe = mask;
mov(probe,
FieldOperand(number_string_cache,
index,
times_twice_pointer_size,
FixedArray::kHeaderSize));
JumpIfSmi(probe, not_found);
fld_d(FieldOperand(object, HeapNumber::kValueOffset));
fld_d(FieldOperand(probe, HeapNumber::kValueOffset));
FCmp();
j(parity_even, not_found); // Bail out if NaN is involved.
j(not_equal, not_found); // The cache did not contain this value.
jmp(&load_result_from_cache, Label::kNear);
bind(&smi_hash_calculated);
// Object is smi and hash is now in scratch. Calculate cache index.
and_(scratch, mask);
// Check if the entry is the smi we are looking for.
cmp(object,
FieldOperand(number_string_cache,
index,
times_twice_pointer_size,
FixedArray::kHeaderSize));
j(not_equal, not_found);
// Get the result from the cache.
bind(&load_result_from_cache);
mov(result,
FieldOperand(number_string_cache,
index,
times_twice_pointer_size,
FixedArray::kHeaderSize + kPointerSize));
IncrementCounter(isolate()->counters()->number_to_string_native(), 1);
}
void MacroAssembler::JumpIfInstanceTypeIsNotSequentialOneByte(
Register instance_type, Register scratch, Label* failure) {
if (!scratch.is(instance_type)) {
......
......@@ -877,17 +877,6 @@ class MacroAssembler: public Assembler {
// ---------------------------------------------------------------------------
// String utilities.
// Generate code to do a lookup in the number string cache. If the number in
// the register object is found in the cache the generated code falls through
// with the result in the result register. The object and the result register
// can be the same. If the number is not found in the cache the code jumps to
// the label not_found with only the content of register object unchanged.
void LookupNumberStringCache(Register object,
Register result,
Register scratch1,
Register scratch2,
Label* not_found);
// Check whether the instance type represents a flat one-byte string. Jump to
// the label if not. If the instance type can be scratched specify same
// register for both instance type and scratch.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment