X87: [stubs] Optimize LoadGlobalViaContextStub and StoreGlobalViaContextStub.
authorchunyang.dai <chunyang.dai@intel.com>
Fri, 24 Jul 2015 10:08:47 +0000 (03:08 -0700)
committerCommit bot <commit-bot@chromium.org>
Fri, 24 Jul 2015 10:08:54 +0000 (10:08 +0000)
port d6ee366d5c5aef7c6bc550889a33520058b4e33a (r29834).

original commit message:

    This is the initial round of optimizations for the
    LoadGlobalViaContextStub and StoreGlobalViaContextStub, basically
    turning them into platform code stubs to avoid the Crankshaft overhead
    in the fast case, and making the runtime interface cheaper.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#29839}

src/x87/code-stubs-x87.cc
src/x87/full-codegen-x87.cc
src/x87/interface-descriptors-x87.cc
src/x87/lithium-codegen-x87.cc
src/x87/macro-assembler-x87.h

index 7f984e9f0111c4310fd64953e0ab58e0fe6fc6d5..48ab6bb270c5deadf637f6e9819a31585f703bfd 100644 (file)
@@ -4776,6 +4776,161 @@ void InternalArrayConstructorStub::Generate(MacroAssembler* masm) {
 }
 
 
+void LoadGlobalViaContextStub::Generate(MacroAssembler* masm) {
+  Register context_reg = esi;
+  Register slot_reg = ebx;
+  Register name_reg = ecx;
+  Register result_reg = eax;
+  Label slow_case;
+
+  // Go up context chain to the script context.
+  for (int i = 0; i < depth(); ++i) {
+    __ mov(result_reg, ContextOperand(context_reg, Context::PREVIOUS_INDEX));
+    context_reg = result_reg;
+  }
+
+  // Load the PropertyCell value at the specified slot.
+  __ mov(result_reg, ContextOperand(context_reg, slot_reg));
+  __ mov(result_reg, FieldOperand(result_reg, PropertyCell::kValueOffset));
+
+  // Check that value is not the_hole.
+  __ CompareRoot(result_reg, Heap::kTheHoleValueRootIndex);
+  __ j(equal, &slow_case, Label::kNear);
+  __ Ret();
+
+  // Fallback to the runtime.
+  __ bind(&slow_case);
+  __ SmiTag(slot_reg);
+  __ Pop(result_reg);  // Pop return address.
+  __ Push(slot_reg);
+  __ Push(name_reg);
+  __ Push(result_reg);  // Push return address.
+  __ TailCallRuntime(Runtime::kLoadGlobalViaContext, 2, 1);
+}
+
+
+void StoreGlobalViaContextStub::Generate(MacroAssembler* masm) {
+  Register context_reg = esi;
+  Register slot_reg = ebx;
+  Register name_reg = ecx;
+  Register value_reg = eax;
+  Register cell_reg = edi;
+  Register cell_details_reg = edx;
+  Label fast_heapobject_case, fast_smi_case, slow_case;
+
+  if (FLAG_debug_code) {
+    __ CompareRoot(value_reg, Heap::kTheHoleValueRootIndex);
+    __ Check(not_equal, kUnexpectedValue);
+    __ AssertName(name_reg);
+  }
+
+  // Go up context chain to the script context.
+  for (int i = 0; i < depth(); ++i) {
+    __ mov(cell_reg, ContextOperand(context_reg, Context::PREVIOUS_INDEX));
+    context_reg = cell_reg;
+  }
+
+  // Load the PropertyCell at the specified slot.
+  __ mov(cell_reg, ContextOperand(context_reg, slot_reg));
+
+  // Load PropertyDetails for the cell (actually only the cell_type and kind).
+  __ mov(cell_details_reg,
+         FieldOperand(cell_reg, PropertyCell::kDetailsOffset));
+  __ SmiUntag(cell_details_reg);
+  __ and_(cell_details_reg,
+          Immediate(PropertyDetails::PropertyCellTypeField::kMask |
+                    PropertyDetails::KindField::kMask));
+
+
+  // Check if PropertyCell holds mutable data.
+  Label not_mutable_data;
+  __ cmp(cell_details_reg,
+         Immediate(PropertyDetails::PropertyCellTypeField::encode(
+                       PropertyCellType::kMutable) |
+                   PropertyDetails::KindField::encode(kData)));
+  __ j(not_equal, &not_mutable_data);
+  __ JumpIfSmi(value_reg, &fast_smi_case);
+  __ bind(&fast_heapobject_case);
+  __ mov(FieldOperand(cell_reg, PropertyCell::kValueOffset), value_reg);
+  __ RecordWriteField(cell_reg, PropertyCell::kValueOffset, value_reg,
+                      cell_details_reg, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+  // RecordWriteField clobbers the value register, so we need to reload.
+  __ mov(value_reg, FieldOperand(cell_reg, PropertyCell::kValueOffset));
+  __ Ret();
+  __ bind(&not_mutable_data);
+
+  // Check if PropertyCell value matches the new value (relevant for Constant,
+  // ConstantType and Undefined cells).
+  Label not_same_value;
+  __ cmp(value_reg, FieldOperand(cell_reg, PropertyCell::kValueOffset));
+  __ j(not_equal, &not_same_value,
+       FLAG_debug_code ? Label::kFar : Label::kNear);
+  if (FLAG_debug_code) {
+    Label done;
+    // This can only be true for Constant, ConstantType and Undefined cells,
+    // because we never store the_hole via this stub.
+    __ cmp(cell_details_reg,
+           Immediate(PropertyDetails::PropertyCellTypeField::encode(
+                         PropertyCellType::kConstant) |
+                     PropertyDetails::KindField::encode(kData)));
+    __ j(equal, &done);
+    __ cmp(cell_details_reg,
+           Immediate(PropertyDetails::PropertyCellTypeField::encode(
+                         PropertyCellType::kConstantType) |
+                     PropertyDetails::KindField::encode(kData)));
+    __ j(equal, &done);
+    __ cmp(cell_details_reg,
+           Immediate(PropertyDetails::PropertyCellTypeField::encode(
+                         PropertyCellType::kUndefined) |
+                     PropertyDetails::KindField::encode(kData)));
+    __ Check(equal, kUnexpectedValue);
+    __ bind(&done);
+  }
+  __ Ret();
+  __ bind(&not_same_value);
+
+  // Check if PropertyCell contains data with constant type.
+  __ cmp(cell_details_reg,
+         Immediate(PropertyDetails::PropertyCellTypeField::encode(
+                       PropertyCellType::kConstantType) |
+                   PropertyDetails::KindField::encode(kData)));
+  __ j(not_equal, &slow_case, Label::kNear);
+
+  // Now either both old and new values must be SMIs or both must be heap
+  // objects with same map.
+  Label value_is_heap_object;
+  Register cell_value_reg = cell_details_reg;
+  __ mov(cell_value_reg, FieldOperand(cell_reg, PropertyCell::kValueOffset));
+  __ JumpIfNotSmi(value_reg, &value_is_heap_object, Label::kNear);
+  __ JumpIfNotSmi(cell_value_reg, &slow_case, Label::kNear);
+  // Old and new values are SMIs, no need for a write barrier here.
+  __ bind(&fast_smi_case);
+  __ mov(FieldOperand(cell_reg, PropertyCell::kValueOffset), value_reg);
+  __ Ret();
+  __ bind(&value_is_heap_object);
+  __ JumpIfSmi(cell_value_reg, &slow_case, Label::kNear);
+  Register cell_value_map_reg = cell_value_reg;
+  __ mov(cell_value_map_reg,
+         FieldOperand(cell_value_reg, HeapObject::kMapOffset));
+  __ cmp(cell_value_map_reg, FieldOperand(value_reg, HeapObject::kMapOffset));
+  __ j(equal, &fast_heapobject_case);
+
+  // Fallback to the runtime.
+  __ bind(&slow_case);
+  __ SmiTag(slot_reg);
+  __ Pop(cell_reg);  // Pop return address.
+  __ Push(slot_reg);
+  __ Push(name_reg);
+  __ Push(value_reg);
+  __ Push(cell_reg);  // Push return address.
+  __ TailCallRuntime(is_strict(language_mode())
+                         ? Runtime::kStoreGlobalViaContext_Strict
+                         : Runtime::kStoreGlobalViaContext_Sloppy,
+                     3, 1);
+}
+
+
 // Generates an Operand for saving parameters after PrepareCallApiFunction.
 static Operand ApiParameterOperand(int index) {
   return Operand(esp, index * kPointerSize);
index dca00d241bb9ce95486a2f6105cb96841b3e2ecd..4640323f7f8641f60e7e73492a86059a39d63dc5 100644 (file)
@@ -1334,15 +1334,18 @@ void FullCodeGenerator::EmitGlobalVariableLoad(VariableProxy* proxy,
     DCHECK(var->index() > 0);
     DCHECK(var->IsStaticGlobalObjectProperty());
     // Each var occupies two slots in the context: for reads and writes.
-    int slot_index = var->index();
-    int depth = scope()->ContextChainLength(var->scope());
-    __ mov(LoadGlobalViaContextDescriptor::DepthRegister(),
-           Immediate(Smi::FromInt(depth)));
-    __ mov(LoadGlobalViaContextDescriptor::SlotRegister(),
-           Immediate(Smi::FromInt(slot_index)));
-    __ mov(LoadGlobalViaContextDescriptor::NameRegister(), var->name());
-    LoadGlobalViaContextStub stub(isolate(), depth);
-    __ CallStub(&stub);
+    int const slot = var->index();
+    int const depth = scope()->ContextChainLength(var->scope());
+    if (depth <= LoadGlobalViaContextStub::kMaximumDepth) {
+      __ Move(LoadGlobalViaContextDescriptor::SlotRegister(), Immediate(slot));
+      __ mov(LoadGlobalViaContextDescriptor::NameRegister(), var->name());
+      LoadGlobalViaContextStub stub(isolate(), depth);
+      __ CallStub(&stub);
+    } else {
+      __ Push(Smi::FromInt(slot));
+      __ Push(var->name());
+      __ CallRuntime(Runtime::kLoadGlobalViaContext, 2);
+    }
 
   } else {
     __ mov(LoadDescriptor::ReceiverRegister(), GlobalObjectOperand());
@@ -2611,16 +2614,23 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
     DCHECK(var->index() > 0);
     DCHECK(var->IsStaticGlobalObjectProperty());
     // Each var occupies two slots in the context: for reads and writes.
-    int slot_index = var->index() + 1;
-    int depth = scope()->ContextChainLength(var->scope());
-    __ mov(StoreGlobalViaContextDescriptor::DepthRegister(),
-           Immediate(Smi::FromInt(depth)));
-    __ mov(StoreGlobalViaContextDescriptor::SlotRegister(),
-           Immediate(Smi::FromInt(slot_index)));
-    __ mov(StoreGlobalViaContextDescriptor::NameRegister(), var->name());
-    DCHECK(StoreGlobalViaContextDescriptor::ValueRegister().is(eax));
-    StoreGlobalViaContextStub stub(isolate(), depth, language_mode());
-    __ CallStub(&stub);
+    int const slot = var->index() + 1;
+    int const depth = scope()->ContextChainLength(var->scope());
+    if (depth <= StoreGlobalViaContextStub::kMaximumDepth) {
+      __ Move(StoreGlobalViaContextDescriptor::SlotRegister(), Immediate(slot));
+      __ mov(StoreGlobalViaContextDescriptor::NameRegister(), var->name());
+      DCHECK(StoreGlobalViaContextDescriptor::ValueRegister().is(eax));
+      StoreGlobalViaContextStub stub(isolate(), depth, language_mode());
+      __ CallStub(&stub);
+    } else {
+      __ Push(Smi::FromInt(slot));
+      __ Push(var->name());
+      __ Push(eax);
+      __ CallRuntime(is_strict(language_mode())
+                         ? Runtime::kStoreGlobalViaContext_Strict
+                         : Runtime::kStoreGlobalViaContext_Sloppy,
+                     3);
+    }
 
   } else if (var->mode() == LET && op != Token::INIT_LET) {
     // Non-initializing assignment to let variable needs a write barrier.
index a71c269f860065bc310cea4bd6442b51e02fa08e..0cbec94f5c1363ef85803b6cfcdb9a1c35de4a34 100644 (file)
@@ -37,12 +37,10 @@ const Register StoreTransitionDescriptor::MapRegister() {
 }
 
 
-const Register LoadGlobalViaContextDescriptor::DepthRegister() { return edx; }
 const Register LoadGlobalViaContextDescriptor::SlotRegister() { return ebx; }
 const Register LoadGlobalViaContextDescriptor::NameRegister() { return ecx; }
 
 
-const Register StoreGlobalViaContextDescriptor::DepthRegister() { return edx; }
 const Register StoreGlobalViaContextDescriptor::SlotRegister() { return ebx; }
 const Register StoreGlobalViaContextDescriptor::NameRegister() { return ecx; }
 const Register StoreGlobalViaContextDescriptor::ValueRegister() { return eax; }
index dc5f2eec7a1f0cdf1124219d165a019d87e63781..ee96cf698801e8c1c0deb3c6e53baad5459891ad 100644 (file)
@@ -3150,15 +3150,19 @@ void LCodeGen::DoLoadGlobalViaContext(LLoadGlobalViaContext* instr) {
   DCHECK(ToRegister(instr->context()).is(esi));
   DCHECK(ToRegister(instr->result()).is(eax));
 
-  __ mov(LoadGlobalViaContextDescriptor::DepthRegister(),
-         Immediate(Smi::FromInt(instr->depth())));
-  __ mov(LoadGlobalViaContextDescriptor::SlotRegister(),
-         Immediate(Smi::FromInt(instr->slot_index())));
-  __ mov(LoadGlobalViaContextDescriptor::NameRegister(), instr->name());
-
-  Handle<Code> stub =
-      CodeFactory::LoadGlobalViaContext(isolate(), instr->depth()).code();
-  CallCode(stub, RelocInfo::CODE_TARGET, instr);
+  int const slot = instr->slot_index();
+  int const depth = instr->depth();
+  if (depth <= LoadGlobalViaContextStub::kMaximumDepth) {
+    __ mov(LoadGlobalViaContextDescriptor::SlotRegister(), slot);
+    __ mov(LoadGlobalViaContextDescriptor::NameRegister(), instr->name());
+    Handle<Code> stub =
+        CodeFactory::LoadGlobalViaContext(isolate(), depth).code();
+    CallCode(stub, RelocInfo::CODE_TARGET, instr);
+  } else {
+    __ Push(Smi::FromInt(slot));
+    __ Push(instr->name());
+    __ CallRuntime(Runtime::kLoadGlobalViaContext, 2);
+  }
 }
 
 
@@ -4546,16 +4550,24 @@ void LCodeGen::DoStoreGlobalViaContext(LStoreGlobalViaContext* instr) {
   DCHECK(ToRegister(instr->value())
              .is(StoreGlobalViaContextDescriptor::ValueRegister()));
 
-  __ mov(StoreGlobalViaContextDescriptor::DepthRegister(),
-         Immediate(Smi::FromInt(instr->depth())));
-  __ mov(StoreGlobalViaContextDescriptor::SlotRegister(),
-         Immediate(Smi::FromInt(instr->slot_index())));
-  __ mov(StoreGlobalViaContextDescriptor::NameRegister(), instr->name());
-
-  Handle<Code> stub =
-      CodeFactory::StoreGlobalViaContext(isolate(), instr->depth(),
-                                         instr->language_mode()).code();
-  CallCode(stub, RelocInfo::CODE_TARGET, instr);
+  int const slot = instr->slot_index();
+  int const depth = instr->depth();
+  if (depth <= StoreGlobalViaContextStub::kMaximumDepth) {
+    __ mov(StoreGlobalViaContextDescriptor::SlotRegister(), slot);
+    __ mov(StoreGlobalViaContextDescriptor::NameRegister(), instr->name());
+    Handle<Code> stub = CodeFactory::StoreGlobalViaContext(
+                            isolate(), depth, instr->language_mode())
+                            .code();
+    CallCode(stub, RelocInfo::CODE_TARGET, instr);
+  } else {
+    __ Push(Smi::FromInt(slot));
+    __ Push(instr->name());
+    __ Push(StoreGlobalViaContextDescriptor::ValueRegister());
+    __ CallRuntime(is_strict(instr->language_mode())
+                       ? Runtime::kStoreGlobalViaContext_Strict
+                       : Runtime::kStoreGlobalViaContext_Sloppy,
+                   3);
+  }
 }
 
 
index 71d538746793210a138a885bdc4c18b7d4331844..02e567dde05691140ba8127c82ca5c7a7cf3bdd5 100644 (file)
@@ -1022,6 +1022,11 @@ inline Operand ContextOperand(Register context, int index) {
 }
 
 
+inline Operand ContextOperand(Register context, Register index) {
+  return Operand(context, index, times_pointer_size, Context::SlotOffset(0));
+}
+
+
 inline Operand GlobalObjectOperand() {
   return ContextOperand(esi, Context::GLOBAL_OBJECT_INDEX);
 }