Revision: 6671
Author: [email protected]
Date: Tue Feb  8 02:08:47 2011
Log: Support %_IsConstructCall in the Crankshaft pipeline.

Provide special case for f.bind(obj).

Review URL: http://codereview.chromium.org/6368138
http://code.google.com/p/v8/source/detail?r=6671

Modified:
 /branches/bleeding_edge/src/arm/lithium-arm.cc
 /branches/bleeding_edge/src/arm/lithium-arm.h
 /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
 /branches/bleeding_edge/src/arm/lithium-codegen-arm.h
 /branches/bleeding_edge/src/hydrogen-instructions.h
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
 /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.h
 /branches/bleeding_edge/src/ia32/lithium-ia32.cc
 /branches/bleeding_edge/src/ia32/lithium-ia32.h
 /branches/bleeding_edge/src/runtime.cc
 /branches/bleeding_edge/src/v8natives.js
 /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
 /branches/bleeding_edge/src/x64/lithium-codegen-x64.h
 /branches/bleeding_edge/src/x64/lithium-x64.cc
 /branches/bleeding_edge/src/x64/lithium-x64.h

=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.cc      Fri Feb  4 05:28:23 2011
+++ /branches/bleeding_edge/src/arm/lithium-arm.cc      Tue Feb  8 02:08:47 2011
@@ -1077,6 +1077,8 @@
     } else if (v->IsTypeofIs()) {
       HTypeofIs* typeof_is = HTypeofIs::cast(v);
       return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
+    } else if (v->IsIsConstructCall()) {
+      return new LIsConstructCallAndBranch(TempRegister());
     } else {
       if (v->IsConstant()) {
         if (HConstant::cast(v)->handle()->IsTrue()) {
@@ -1889,6 +1891,12 @@
 LInstruction* LChunkBuilder::DoTypeofIs(HTypeofIs* instr) {
   return DefineSameAsFirst(new LTypeofIs(UseRegister(instr->value())));
 }
+
+
+LInstruction* LChunkBuilder::DoIsConstructCall(HIsConstructCall* instr) {
+  return DefineAsRegister(new LIsConstructCall());
+}
+

 LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
   HEnvironment* env = current_block_->last_environment();
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.h       Fri Feb  4 05:46:09 2011
+++ /branches/bleeding_edge/src/arm/lithium-arm.h       Tue Feb  8 02:08:47 2011
@@ -153,6 +153,8 @@
   V(Typeof)                                     \
   V(TypeofIs)                                   \
   V(TypeofIsAndBranch)                          \
+  V(IsConstructCall)                            \
+  V(IsConstructCallAndBranch)                   \
   V(UnaryMathOperation)                         \
   V(UnknownOSRValue)                            \
   V(ValueOf)
@@ -1716,6 +1718,24 @@
 };


+class LIsConstructCall: public LTemplateInstruction<1, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(IsConstructCall, "is-construct-call")
+  DECLARE_HYDROGEN_ACCESSOR(IsConstructCall)
+};
+
+
+class LIsConstructCallAndBranch: public LControlInstruction<0, 1> {
+ public:
+  explicit LIsConstructCallAndBranch(LOperand* temp) {
+    temps_[0] = temp;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch,
+                               "is-construct-call-and-branch")
+};
+
+
 class LDeleteProperty: public LTemplateInstruction<1, 2, 0> {
  public:
   LDeleteProperty(LOperand* obj, LOperand* key) {
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Sun Feb 6 23:39:40 2011 +++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Tue Feb 8 02:08:47 2011
@@ -3776,6 +3776,55 @@

   return final_branch_condition;
 }
+
+
+void LCodeGen::DoIsConstructCall(LIsConstructCall* instr) {
+  Register result = ToRegister(instr->result());
+  Label true_label;
+  Label false_label;
+  Label done;
+
+  EmitIsConstructCall(result, scratch0());
+  __ b(eq, &true_label);
+
+  __ LoadRoot(result, Heap::kFalseValueRootIndex);
+  __ b(&done);
+
+
+  __ bind(&true_label);
+  __ LoadRoot(result, Heap::kTrueValueRootIndex);
+
+  __ bind(&done);
+}
+
+
+void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
+  Register temp1 = ToRegister(instr->TempAt(0));
+  int true_block = chunk_->LookupDestination(instr->true_block_id());
+  int false_block = chunk_->LookupDestination(instr->false_block_id());
+
+  EmitIsConstructCall(temp1, scratch0());
+  EmitBranch(true_block, false_block, eq);
+}
+
+
+void LCodeGen::EmitIsConstructCall(Register temp1, Register temp2) {
+  ASSERT(!temp1.is(temp2));
+  // Get the frame pointer for the calling frame.
+  __ ldr(temp1, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+
+  // Skip the arguments adaptor frame if it exists.
+  Label check_frame_marker;
+  __ ldr(temp2, MemOperand(temp1, StandardFrameConstants::kContextOffset));
+  __ cmp(temp2, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
+  __ b(ne, &check_frame_marker);
+ __ ldr(temp1, MemOperand(temp1, StandardFrameConstants::kCallerFPOffset));
+
+  // Check the marker in the calling frame.
+  __ bind(&check_frame_marker);
+  __ ldr(temp1, MemOperand(temp1, StandardFrameConstants::kMarkerOffset));
+  __ cmp(temp1, Operand(Smi::FromInt(StackFrame::CONSTRUCT)));
+}


 void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.h Thu Feb 3 23:08:50 2011 +++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.h Tue Feb 8 02:08:47 2011
@@ -264,6 +264,10 @@
                          Label* is_not_object,
                          Label* is_object);

+  // Emits optimized code for %_IsConstructCall().
+  // Caller should branch on equal condition.
+  void EmitIsConstructCall(Register temp1, Register temp2);
+
   LChunk* const chunk_;
   MacroAssembler* const masm_;
   CompilationInfo* const info_;
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Thu Feb 3 05:10:28 2011 +++ /branches/bleeding_edge/src/hydrogen-instructions.h Tue Feb 8 02:08:47 2011
@@ -113,6 +113,7 @@
   V(IsNull)                                    \
   V(IsObject)                                  \
   V(IsSmi)                                     \
+  V(IsConstructCall)                           \
   V(HasInstanceType)                           \
   V(HasCachedArrayIndex)                       \
   V(JSArrayLength)                             \
@@ -2179,6 +2180,22 @@
 };


+class HIsConstructCall: public HInstruction {
+ public:
+  HIsConstructCall() {
+    set_representation(Representation::Tagged());
+    SetFlag(kUseGVN);
+  }
+
+  virtual bool EmitAtUses() const { return uses()->length() <= 1; }
+
+  DECLARE_CONCRETE_INSTRUCTION(IsConstructCall, "is_construct_call")
+
+ protected:
+  virtual bool DataEquals(HValue* other) const { return true; }
+};
+
+
 class HHasInstanceType: public HUnaryPredicate {
  public:
   HHasInstanceType(HValue* value, InstanceType type)
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Thu Feb  3 05:10:28 2011
+++ /branches/bleeding_edge/src/hydrogen.cc     Tue Feb  8 02:08:47 2011
@@ -5185,9 +5185,10 @@
 }


-  // Support for construct call checks.
+// Support for construct call checks.
void HGraphBuilder::GenerateIsConstructCall(int argument_count, int ast_id) {
-  BAILOUT("inlined runtime function: IsConstructCall");
+  ASSERT(argument_count == 0);
+  ast_context()->ReturnInstruction(new HIsConstructCall, ast_id);
 }


=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Mon Feb 7 23:49:59 2011 +++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Tue Feb 8 02:08:47 2011
@@ -3585,6 +3585,53 @@

   return final_branch_condition;
 }
+
+
+void LCodeGen::DoIsConstructCall(LIsConstructCall* instr) {
+  Register result = ToRegister(instr->result());
+  NearLabel true_label;
+  NearLabel false_label;
+  NearLabel done;
+
+  EmitIsConstructCall(result);
+  __ j(equal, &true_label);
+
+  __ mov(result, Factory::false_value());
+  __ jmp(&done);
+
+  __ bind(&true_label);
+  __ mov(result, Factory::true_value());
+
+  __ bind(&done);
+}
+
+
+void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
+  Register temp = ToRegister(instr->TempAt(0));
+  int true_block = chunk_->LookupDestination(instr->true_block_id());
+  int false_block = chunk_->LookupDestination(instr->false_block_id());
+
+  EmitIsConstructCall(temp);
+  EmitBranch(true_block, false_block, equal);
+}
+
+
+void LCodeGen::EmitIsConstructCall(Register temp) {
+  // Get the frame pointer for the calling frame.
+  __ mov(temp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
+
+  // Skip the arguments adaptor frame if it exists.
+  NearLabel check_frame_marker;
+  __ cmp(Operand(temp, StandardFrameConstants::kContextOffset),
+         Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
+  __ j(not_equal, &check_frame_marker);
+  __ mov(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset));
+
+  // Check the marker in the calling frame.
+  __ bind(&check_frame_marker);
+  __ cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
+         Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
+}


 void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.h Wed Jan 26 12:48:48 2011 +++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.h Tue Feb 8 02:08:47 2011
@@ -229,6 +229,11 @@
                          Label* is_not_object,
                          Label* is_object);

+  // Emits optimized code for %_IsConstructCall().
+  // Caller should branch on equal condition.
+  void EmitIsConstructCall(Register temp);
+
+
   LChunk* const chunk_;
   MacroAssembler* const masm_;
   CompilationInfo* const info_;
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.cc Fri Feb 4 05:28:23 2011 +++ /branches/bleeding_edge/src/ia32/lithium-ia32.cc Tue Feb 8 02:08:47 2011
@@ -1098,6 +1098,8 @@
     } else if (v->IsTypeofIs()) {
       HTypeofIs* typeof_is = HTypeofIs::cast(v);
       return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
+    } else if (v->IsIsConstructCall()) {
+      return new LIsConstructCallAndBranch(TempRegister());
     } else {
       if (v->IsConstant()) {
         if (HConstant::cast(v)->handle()->IsTrue()) {
@@ -1924,6 +1926,12 @@
 LInstruction* LChunkBuilder::DoTypeofIs(HTypeofIs* instr) {
   return DefineSameAsFirst(new LTypeofIs(UseRegister(instr->value())));
 }
+
+
+LInstruction* LChunkBuilder::DoIsConstructCall(HIsConstructCall* instr) {
+  return DefineAsRegister(new LIsConstructCall);
+}
+

 LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
   HEnvironment* env = current_block_->last_environment();
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.h     Fri Feb  4 05:28:23 2011
+++ /branches/bleeding_edge/src/ia32/lithium-ia32.h     Tue Feb  8 02:08:47 2011
@@ -112,6 +112,8 @@
   V(IsObjectAndBranch)                          \
   V(IsSmi)                                      \
   V(IsSmiAndBranch)                             \
+  V(IsConstructCall)                            \
+  V(IsConstructCallAndBranch)                   \
   V(JSArrayLength)                              \
   V(Label)                                      \
   V(LazyBailout)                                \
@@ -755,6 +757,24 @@
 };


+class LIsConstructCall: public LTemplateInstruction<1, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(IsConstructCall, "is-construct-call")
+  DECLARE_HYDROGEN_ACCESSOR(IsConstructCall)
+};
+
+
+class LIsConstructCallAndBranch: public LControlInstruction<0, 1> {
+ public:
+  explicit LIsConstructCallAndBranch(LOperand* temp) {
+    temps_[0] = temp;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch,
+                               "is-construct-call-and-branch")
+};
+
+
 class LClassOfTest: public LTemplateInstruction<1, 1, 1> {
  public:
   LClassOfTest(LOperand* value, LOperand* temp) {
=======================================
--- /branches/bleeding_edge/src/runtime.cc      Fri Feb  4 10:15:49 2011
+++ /branches/bleeding_edge/src/runtime.cc      Tue Feb  8 02:08:47 2011
@@ -6680,29 +6680,51 @@
                                                  pretenure_flag);
   return *result;
 }
+

 static MaybeObject* Runtime_NewObjectFromBound(Arguments args) {
   HandleScope scope;
   ASSERT(args.length() == 2);
+  // First argument is a function to use as a constructor.
   CONVERT_ARG_CHECKED(JSFunction, function, 0);
-  CONVERT_ARG_CHECKED(JSArray, params, 1);
-
-  RUNTIME_ASSERT(params->HasFastElements());
-  FixedArray* fixed = FixedArray::cast(params->elements());
-
-  int fixed_length = Smi::cast(params->length())->value();
-  SmartPointer<Object**> param_data(NewArray<Object**>(fixed_length));
-  for (int i = 0; i < fixed_length; i++) {
-    Handle<Object> val = Handle<Object>(fixed->get(i));
+
+  // Second argument is either null or an array of bound arguments.
+  FixedArray* bound_args = NULL;
+  int bound_argc = 0;
+  if (!args[1]->IsNull()) {
+    CONVERT_ARG_CHECKED(JSArray, params, 1);
+    RUNTIME_ASSERT(params->HasFastElements());
+    bound_args = FixedArray::cast(params->elements());
+    bound_argc = Smi::cast(params->length())->value();
+  }
+
+  // Find frame containing arguments passed to the caller.
+  JavaScriptFrameIterator it;
+  JavaScriptFrame* frame = it.frame();
+  ASSERT(!frame->is_optimized());
+  it.AdvanceToArgumentsFrame();
+  frame = it.frame();
+  int argc = frame->GetProvidedParametersCount();
+
+  // Prepend bound arguments to caller's arguments.
+  int total_argc = bound_argc + argc;
+  SmartPointer<Object**> param_data(NewArray<Object**>(total_argc));
+  for (int i = 0; i < bound_argc; i++) {
+    Handle<Object> val = Handle<Object>(bound_args->get(i));
     param_data[i] = val.location();
   }
+  for (int i = 0; i < argc; i++) {
+    Handle<Object> val = Handle<Object>(frame->GetParameter(i));
+    param_data[bound_argc + i] = val.location();
+  }

   bool exception = false;
-  Handle<Object> result = Execution::New(
-      function, fixed_length, *param_data, &exception);
+  Handle<Object> result =
+      Execution::New(function, total_argc, *param_data, &exception);
   if (exception) {
       return Failure::Exception();
   }
+
   ASSERT(!result.is_null());
   return *result;
 }
=======================================
--- /branches/bleeding_edge/src/v8natives.js    Fri Feb  4 04:14:56 2011
+++ /branches/bleeding_edge/src/v8natives.js    Tue Feb  8 02:08:47 2011
@@ -1153,33 +1153,49 @@
   }
   // this_arg is not an argument that should be bound.
   var argc_bound = (%_ArgumentsLength() || 1) - 1;
-  if (argc_bound > 0) {
+  var fn = this;
+  if (argc_bound == 0) {
+    var result = function() {
+      if (%_IsConstructCall()) {
+        // %NewObjectFromBound implicitly uses arguments passed to this
+ // function. We do not pass the arguments object explicitly to avoid + // materializing it and guarantee that this function will be optimized.
+        return %NewObjectFromBound(fn, null);
+      }
+
+      return fn.apply(this_arg, arguments);
+    };
+  } else {
     var bound_args = new $Array(argc_bound);
     for(var i = 0; i < argc_bound; i++) {
       bound_args[i] = %_Arguments(i+1);
     }
-  }
-  var fn = this;
-  var result = function() {
-    // Combine the args we got from the bind call with the args
-    // given as argument to the invocation.
-    var argc = %_ArgumentsLength();
-    var args = new $Array(argc + argc_bound);
-    // Add bound arguments.
-    for (var i = 0; i < argc_bound; i++) {
-      args[i] = bound_args[i];
-    }
-    // Add arguments from call.
-    for (var i = 0; i < argc; i++) {
-      args[argc_bound + i] = %_Arguments(i);
-    }
-    // If this is a construct call we use a special runtime method
-    // to generate the actual object using the bound function.
-    if (%_IsConstructCall()) {
-      return %NewObjectFromBound(fn, args);
-    }
-    return fn.apply(this_arg, args);
-  };
+
+    var result = function() {
+      // If this is a construct call we use a special runtime method
+      // to generate the actual object using the bound function.
+      if (%_IsConstructCall()) {
+        // %NewObjectFromBound implicitly uses arguments passed to this
+ // function. We do not pass the arguments object explicitly to avoid + // materializing it and guarantee that this function will be optimized.
+        return %NewObjectFromBound(fn, bound_args);
+      }
+
+      // Combine the args we got from the bind call with the args
+      // given as argument to the invocation.
+      var argc = %_ArgumentsLength();
+      var args = new $Array(argc + argc_bound);
+      // Add bound arguments.
+      for (var i = 0; i < argc_bound; i++) {
+        args[i] = bound_args[i];
+      }
+      // Add arguments from call.
+      for (var i = 0; i < argc; i++) {
+        args[argc_bound + i] = %_Arguments(i);
+      }
+      return fn.apply(this_arg, args);
+    };
+  }

   // We already have caller and arguments properties on functions,
   // which are non-configurable. It therefore makes no sence to
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Tue Feb 8 01:43:24 2011 +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Tue Feb 8 02:08:47 2011
@@ -2282,6 +2282,54 @@
 void LCodeGen::DoTypeofIs(LTypeofIs* instr) {
   Abort("Unimplemented: %s", "DoTypeofIs");
 }
+
+
+void LCodeGen::DoIsConstructCall(LIsConstructCall* instr) {
+  Register result = ToRegister(instr->result());
+  NearLabel true_label;
+  NearLabel false_label;
+  NearLabel done;
+
+  EmitIsConstructCall(result);
+  __ j(equal, &true_label);
+
+  __ LoadRoot(result, Heap::kFalseValueRootIndex);
+  __ jmp(&done);
+
+  __ bind(&true_label);
+  __ LoadRoot(result, Heap::kTrueValueRootIndex);
+
+
+  __ bind(&done);
+}
+
+
+void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
+  Register temp = ToRegister(instr->TempAt(0));
+  int true_block = chunk_->LookupDestination(instr->true_block_id());
+  int false_block = chunk_->LookupDestination(instr->false_block_id());
+
+  EmitIsConstructCall(temp);
+  EmitBranch(true_block, false_block, equal);
+}
+
+
+void LCodeGen::EmitIsConstructCall(Register temp) {
+  // Get the frame pointer for the calling frame.
+  __ movq(temp, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
+
+  // Skip the arguments adaptor frame if it exists.
+  NearLabel check_frame_marker;
+  __ SmiCompare(Operand(temp, StandardFrameConstants::kContextOffset),
+                Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
+  __ j(not_equal, &check_frame_marker);
+  __ movq(temp, Operand(rax, StandardFrameConstants::kCallerFPOffset));
+
+  // Check the marker in the calling frame.
+  __ bind(&check_frame_marker);
+  __ SmiCompare(Operand(temp, StandardFrameConstants::kMarkerOffset),
+                Smi::FromInt(StackFrame::CONSTRUCT));
+}


 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.h Wed Jan 26 12:48:48 2011 +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.h Tue Feb 8 02:08:47 2011
@@ -221,6 +221,10 @@
                          Label* is_not_object,
                          Label* is_object);

+  // Emits optimized code for %_IsConstructCall().
+  // Caller should branch on equal condition.
+  void EmitIsConstructCall(Register temp);
+
   LChunk* const chunk_;
   MacroAssembler* const masm_;
   CompilationInfo* const info_;
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.cc      Mon Feb  7 23:49:59 2011
+++ /branches/bleeding_edge/src/x64/lithium-x64.cc      Tue Feb  8 02:08:47 2011
@@ -1082,6 +1082,8 @@
     } else if (v->IsTypeofIs()) {
       HTypeofIs* typeof_is = HTypeofIs::cast(v);
       return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
+    } else if (v->IsIsConstructCall()) {
+      return new LIsConstructCallAndBranch(TempRegister());
     } else {
       if (v->IsConstant()) {
         if (HConstant::cast(v)->handle()->IsTrue()) {
@@ -1774,6 +1776,12 @@
   Abort("Unimplemented: %s", "DoTypeofIs");
   return NULL;
 }
+
+
+LInstruction* LChunkBuilder::DoIsConstructCall(HIsConstructCall* instr) {
+  return DefineAsRegister(new LIsConstructCall);
+}
+

 LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
   HEnvironment* env = current_block_->last_environment();
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.h       Fri Feb  4 06:09:03 2011
+++ /branches/bleeding_edge/src/x64/lithium-x64.h       Tue Feb  8 02:08:47 2011
@@ -259,6 +259,8 @@
   V(Typeof)                                     \
   V(TypeofIs)                                   \
   V(TypeofIsAndBranch)                          \
+  V(IsConstructCall)                            \
+  V(IsConstructCallAndBranch)                   \
   V(UnaryMathOperation)                         \
   V(UnknownOSRValue)                            \
   V(ValueOf)
@@ -1763,6 +1765,24 @@
 };


+class LIsConstructCall: public LTemplateInstruction<1, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(IsConstructCall, "is-construct-call")
+  DECLARE_HYDROGEN_ACCESSOR(IsConstructCall)
+};
+
+
+class LIsConstructCallAndBranch: public LControlInstruction<0, 1> {
+ public:
+  explicit LIsConstructCallAndBranch(LOperand* temp) {
+    temps_[0] = temp;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch,
+                               "is-construct-call-and-branch")
+};
+
+
 class LDeleteProperty: public LTemplateInstruction<1, 2, 0> {
  public:
   LDeleteProperty(LOperand* obj, LOperand* key) {

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to