| Index: src/ia32/stub-cache-ia32.cc
|
| diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
|
| index d5bb26f07f8dccd09783991a7059498c57af40d2..d2fe79d36b31166a762bdb888def07d190acce3c 100644
|
| --- a/src/ia32/stub-cache-ia32.cc
|
| +++ b/src/ia32/stub-cache-ia32.cc
|
| @@ -858,9 +858,14 @@ MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCell(
|
| }
|
| JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe);
|
| ASSERT(cell->value()->IsTheHole());
|
| - __ mov(scratch, Immediate(Handle<Object>(cell)));
|
| - __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
|
| - Immediate(FACTORY->the_hole_value()));
|
| + if (Serializer::enabled()) {
|
| + __ mov(scratch, Immediate(Handle<Object>(cell)));
|
| + __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset),
|
| + Immediate(FACTORY->the_hole_value()));
|
| + } else {
|
| + __ cmp(Operand::Cell(Handle<JSGlobalPropertyCell>(cell)),
|
| + Immediate(FACTORY->the_hole_value()));
|
| + }
|
| __ j(not_equal, miss, not_taken);
|
| return cell;
|
| }
|
| @@ -1329,8 +1334,12 @@ void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell,
|
| JSFunction* function,
|
| Label* miss) {
|
| // Get the value from the cell.
|
| - __ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell)));
|
| - __ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset));
|
| + if (Serializer::enabled()) {
|
| + __ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell)));
|
| + __ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset));
|
| + } else {
|
| + __ mov(edi, Operand::Cell(Handle<JSGlobalPropertyCell>(cell)));
|
| + }
|
|
|
| // Check that the cell contains the same function.
|
| if (HEAP->InNewSpace(function)) {
|
| @@ -1713,7 +1722,7 @@ MaybeObject* CallStubCompiler::CompileStringCharCodeAtCall(
|
| char_code_at_generator.GenerateFast(masm());
|
| __ ret((argc + 1) * kPointerSize);
|
|
|
| - ICRuntimeCallHelper call_helper;
|
| + StubRuntimeCallHelper call_helper;
|
| char_code_at_generator.GenerateSlow(masm(), call_helper);
|
|
|
| __ bind(&index_out_of_range);
|
| @@ -1788,7 +1797,7 @@ MaybeObject* CallStubCompiler::CompileStringCharAtCall(
|
| char_at_generator.GenerateFast(masm());
|
| __ ret((argc + 1) * kPointerSize);
|
|
|
| - ICRuntimeCallHelper call_helper;
|
| + StubRuntimeCallHelper call_helper;
|
| char_at_generator.GenerateSlow(masm(), call_helper);
|
|
|
| __ bind(&index_out_of_range);
|
| @@ -1861,7 +1870,7 @@ MaybeObject* CallStubCompiler::CompileStringFromCharCodeCall(
|
| char_from_code_generator.GenerateFast(masm());
|
| __ ret(2 * kPointerSize);
|
|
|
| - ICRuntimeCallHelper call_helper;
|
| + StubRuntimeCallHelper call_helper;
|
| char_from_code_generator.GenerateSlow(masm(), call_helper);
|
|
|
| // Tail call the full function. We do not have to patch the receiver
|
| @@ -2403,10 +2412,18 @@ MaybeObject* CallStubCompiler::CompileCallGlobal(JSObject* object,
|
| // Jump to the cached code (tail call).
|
| __ IncrementCounter(COUNTERS->call_global_inline(), 1);
|
| ASSERT(function->is_compiled());
|
| - Handle<Code> code(function->code());
|
| ParameterCount expected(function->shared()->formal_parameter_count());
|
| - __ InvokeCode(code, expected, arguments(),
|
| - RelocInfo::CODE_TARGET, JUMP_FUNCTION);
|
| + if (V8::UseCrankshaft()) {
|
| + // TODO(kasperl): For now, we always call indirectly through the
|
| + // code field in the function to allow recompilation to take effect
|
| + // without changing any of the call sites.
|
| + __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
|
| + expected, arguments(), JUMP_FUNCTION);
|
| + } else {
|
| + Handle<Code> code(function->code());
|
| + __ InvokeCode(code, expected, arguments(),
|
| + RelocInfo::CODE_TARGET, JUMP_FUNCTION);
|
| + }
|
|
|
| // Handle call cache miss.
|
| __ bind(&miss);
|
| @@ -2572,8 +2589,12 @@ MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
|
| __ j(not_equal, &miss, not_taken);
|
|
|
| // Store the value in the cell.
|
| - __ mov(ecx, Immediate(Handle<JSGlobalPropertyCell>(cell)));
|
| - __ mov(FieldOperand(ecx, JSGlobalPropertyCell::kValueOffset), eax);
|
| + if (Serializer::enabled()) {
|
| + __ mov(ecx, Immediate(Handle<JSGlobalPropertyCell>(cell)));
|
| + __ mov(FieldOperand(ecx, JSGlobalPropertyCell::kValueOffset), eax);
|
| + } else {
|
| + __ mov(Operand::Cell(Handle<JSGlobalPropertyCell>(cell)), eax);
|
| + }
|
|
|
| // Return the value (register eax).
|
| __ IncrementCounter(COUNTERS->named_store_global_inline(), 1);
|
| @@ -2629,6 +2650,64 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
|
| }
|
|
|
|
|
| +MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized(
|
| + JSObject* receiver) {
|
| + // ----------- S t a t e -------------
|
| + // -- eax : value
|
| + // -- ecx : key
|
| + // -- edx : receiver
|
| + // -- esp[0] : return address
|
| + // -----------------------------------
|
| + Label miss;
|
| +
|
| + // Check that the receiver isn't a smi.
|
| + __ test(edx, Immediate(kSmiTagMask));
|
| + __ j(zero, &miss, not_taken);
|
| +
|
| + // Check that the map matches.
|
| + __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
|
| + Immediate(Handle<Map>(receiver->map())));
|
| + __ j(not_equal, &miss, not_taken);
|
| +
|
| + // Check that the key is a smi.
|
| + __ test(ecx, Immediate(kSmiTagMask));
|
| + __ j(not_zero, &miss, not_taken);
|
| +
|
| + // Get the elements array and make sure it is a fast element array, not 'cow'.
|
| + __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
|
| + __ cmp(FieldOperand(edi, HeapObject::kMapOffset),
|
| + Immediate(FACTORY->fixed_array_map()));
|
| + __ j(not_equal, &miss, not_taken);
|
| +
|
| + // Check that the key is within bounds.
|
| + if (receiver->IsJSArray()) {
|
| + __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis.
|
| + __ j(above_equal, &miss, not_taken);
|
| + } else {
|
| + __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // Compare smis.
|
| + __ j(above_equal, &miss, not_taken);
|
| + }
|
| +
|
| + // Do the store and update the write barrier. Make sure to preserve
|
| + // the value in register eax.
|
| + __ mov(edx, Operand(eax));
|
| + __ mov(FieldOperand(edi, ecx, times_2, FixedArray::kHeaderSize), eax);
|
| + __ RecordWrite(edi, 0, edx, ecx);
|
| +
|
| + // Done.
|
| + __ ret(0);
|
| +
|
| + // Handle store cache miss.
|
| + __ bind(&miss);
|
| + Handle<Code> ic(
|
| + Isolate::Current()->builtins()->builtin(Builtins::KeyedStoreIC_Miss));
|
| + __ jmp(ic, RelocInfo::CODE_TARGET);
|
| +
|
| + // Return the generated code.
|
| + return GetCode(NORMAL, NULL);
|
| +}
|
| +
|
| +
|
| MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name,
|
| JSObject* object,
|
| JSObject* last) {
|
| @@ -2802,8 +2881,12 @@ MaybeObject* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
|
| CheckPrototypes(object, eax, holder, ebx, edx, edi, name, &miss);
|
|
|
| // Get the value from the cell.
|
| - __ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell)));
|
| - __ mov(ebx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset));
|
| + if (Serializer::enabled()) {
|
| + __ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell)));
|
| + __ mov(ebx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset));
|
| + } else {
|
| + __ mov(ebx, Operand::Cell(Handle<JSGlobalPropertyCell>(cell)));
|
| + }
|
|
|
| // Check for deleted property if property can actually be deleted.
|
| if (!is_dont_delete) {
|
| @@ -3028,6 +3111,51 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
|
| }
|
|
|
|
|
| +MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) {
|
| + // ----------- S t a t e -------------
|
| + // -- eax : key
|
| + // -- edx : receiver
|
| + // -- esp[0] : return address
|
| + // -----------------------------------
|
| + Label miss;
|
| +
|
| + // Check that the receiver isn't a smi.
|
| + __ test(edx, Immediate(kSmiTagMask));
|
| + __ j(zero, &miss, not_taken);
|
| +
|
| + // Check that the map matches.
|
| + __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
|
| + Immediate(Handle<Map>(receiver->map())));
|
| + __ j(not_equal, &miss, not_taken);
|
| +
|
| + // Check that the key is a smi.
|
| + __ test(eax, Immediate(kSmiTagMask));
|
| + __ j(not_zero, &miss, not_taken);
|
| +
|
| + // Get the elements array.
|
| + __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
|
| + __ AssertFastElements(ecx);
|
| +
|
| + // Check that the key is within bounds.
|
| + __ cmp(eax, FieldOperand(ecx, FixedArray::kLengthOffset));
|
| + __ j(above_equal, &miss, not_taken);
|
| +
|
| + // Load the result and make sure it's not the hole.
|
| + __ mov(ebx, Operand(ecx, eax, times_2,
|
| + FixedArray::kHeaderSize - kHeapObjectTag));
|
| + __ cmp(ebx, FACTORY->the_hole_value());
|
| + __ j(equal, &miss, not_taken);
|
| + __ mov(eax, ebx);
|
| + __ ret(0);
|
| +
|
| + __ bind(&miss);
|
| + GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
|
| +
|
| + // Return the generated code.
|
| + return GetCode(NORMAL, NULL);
|
| +}
|
| +
|
| +
|
| // Specialized stub for constructing objects from functions which only have only
|
| // simple assignments of the form this.x = ...; in their body.
|
| MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
|
|
|