// r1 (receiver). Touch up the stack with the right values.
__ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ str(r1, MemOperand(sp, arg_count * kPointerSize));
+
+ PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
}
// Record source position for debugger.
__ Push(context_register(), r2);
__ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ Push(r0, r1); // Function, receiver.
+ PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the
// function and receiver and have the slow path jump around this
// The runtime call returns a pair of values in x0 (function) and
// x1 (receiver). Touch up the stack with the right values.
__ PokePair(x1, x0, arg_count * kPointerSize);
+
+ PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
}
// Record source position for debugger.
__ Push(context_register(), x10);
__ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ Push(x0, x1); // Receiver, function.
+ PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the
// function and receiver and have the slow path jump around this
bool ComputeGlobalTarget(Handle<GlobalObject> global, LookupIterator* it);
BailoutId ReturnId() const { return return_id_; }
+ BailoutId EvalOrLookupId() const { return eval_or_lookup_id_; }
enum CallType {
POSSIBLY_EVAL_CALL,
expression_(expression),
arguments_(arguments),
call_feedback_slot_(kInvalidFeedbackSlot),
- return_id_(id_gen->GetNextId()) {
+ return_id_(id_gen->GetNextId()),
+ eval_or_lookup_id_(id_gen->GetNextId()) {
if (expression->IsProperty()) {
expression->AsProperty()->mark_for_call();
}
int call_feedback_slot_;
const BailoutId return_id_;
+ // TODO(jarin) Only allocate the bailout id for the POSSIBLY_EVAL_CALL and
+ // LOOKUP_SLOT_CALL types.
+ const BailoutId eval_or_lookup_id_;
};
const Operator* op =
javascript()->Runtime(Runtime::kMaterializeRegExpLiteral, 4);
Node* literal = NewNode(op, literals_array, literal_index, pattern, flags);
+ PrepareFrameState(literal, expr->id(), ast_context()->GetStateCombine());
ast_context()->ProduceValue(literal);
}
Unique<Name> name =
MakeUnique(property->key()->AsLiteral()->AsPropertyName());
old_value = NewNode(javascript()->LoadNamed(name), object);
- PrepareFrameState(old_value, property->LoadId(), kPushOutput);
+ PrepareFrameState(old_value, property->LoadId(),
+ OutputFrameStateCombine::Push());
break;
}
case KEYED_PROPERTY: {
Node* key = environment()->Top();
Node* object = environment()->Peek(1);
old_value = NewNode(javascript()->LoadProperty(), object, key);
- PrepareFrameState(old_value, property->LoadId(), kPushOutput);
+ PrepareFrameState(old_value, property->LoadId(),
+ OutputFrameStateCombine::Push());
break;
}
}
Node* right = environment()->Pop();
Node* left = environment()->Pop();
Node* value = BuildBinaryOp(left, right, expr->binary_op());
- PrepareFrameState(value, expr->binary_operation()->id(), kPushOutput);
+ PrepareFrameState(value, expr->binary_operation()->id(),
+ OutputFrameStateCombine::Push());
environment()->Push(value);
} else {
VisitForValue(expr->value());
Node* exception = environment()->Pop();
const Operator* op = javascript()->Runtime(Runtime::kThrow, 1);
Node* value = NewNode(op, exception);
+ PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
ast_context()->ProduceValue(value);
}
Node* pair = NewNode(op, current_context(), name);
callee_value = NewNode(common()->Projection(0), pair);
receiver_value = NewNode(common()->Projection(1), pair);
+
+ PrepareFrameState(pair, expr->EvalOrLookupId(),
+ OutputFrameStateCombine::Push());
break;
}
case Call::PROPERTY_CALL: {
Node* key = environment()->Pop();
callee_value = NewNode(javascript()->LoadProperty(), object, key);
}
- PrepareFrameState(callee_value, property->LoadId(), kPushOutput);
+ PrepareFrameState(callee_value, property->LoadId(),
+ OutputFrameStateCombine::Push());
receiver_value = environment()->Pop();
// Note that a PROPERTY_CALL requires the receiver to be wrapped into an
// object for sloppy callees. This could also be modeled explicitly here,
const Operator* op =
javascript()->Runtime(Runtime::kResolvePossiblyDirectEval, 5);
Node* pair = NewNode(op, callee, source, receiver, strict, position);
+ PrepareFrameState(pair, expr->EvalOrLookupId(),
+ OutputFrameStateCombine::PokeAt(arg_count + 1));
Node* new_callee = NewNode(common()->Projection(0), pair);
Node* new_receiver = NewNode(common()->Projection(1), pair);
Node* callee_value = NewNode(javascript()->LoadNamed(unique), receiver_value);
// TODO(jarin): Find/create a bailout id to deoptimize to (crankshaft
// refuses to optimize functions with jsruntime calls).
- PrepareFrameState(callee_value, BailoutId::None(), kPushOutput);
+ PrepareFrameState(callee_value, BailoutId::None(),
+ OutputFrameStateCombine::Push());
environment()->Push(callee_value);
environment()->Push(receiver_value);
Unique<Name> name =
MakeUnique(property->key()->AsLiteral()->AsPropertyName());
old_value = NewNode(javascript()->LoadNamed(name), object);
- PrepareFrameState(old_value, property->LoadId(), kPushOutput);
+ PrepareFrameState(old_value, property->LoadId(),
+ OutputFrameStateCombine::Push());
stack_depth = 1;
break;
}
Node* key = environment()->Top();
Node* object = environment()->Peek(1);
old_value = NewNode(javascript()->LoadProperty(), object, key);
- PrepareFrameState(old_value, property->LoadId(), kPushOutput);
+ PrepareFrameState(old_value, property->LoadId(),
+ OutputFrameStateCombine::Push());
stack_depth = 2;
break;
}
// deleting "this" is allowed in all language modes.
Variable* variable = expr->expression()->AsVariableProxy()->var();
DCHECK(strict_mode() == SLOPPY || variable->is_this());
- value = BuildVariableDelete(variable);
+ value = BuildVariableDelete(variable, expr->id(),
+ ast_context()->GetStateCombine());
} else if (expr->expression()->IsProperty()) {
Property* property = expr->expression()->AsProperty();
VisitForValue(property->obj());
Node* key = environment()->Pop();
Node* object = environment()->Pop();
value = NewNode(javascript()->DeleteProperty(strict_mode()), object, key);
+ PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
} else {
VisitForEffect(expr->expression());
value = jsgraph()->TrueConstant();
Node* AstGraphBuilder::BuildHoleCheckThrow(Node* value, Variable* variable,
- Node* not_hole) {
+ Node* not_hole,
+ BailoutId bailout_id) {
IfBuilder hole_check(this);
Node* the_hole = jsgraph()->TheHoleConstant();
Node* check = NewNode(javascript()->StrictEqual(), value, the_hole);
hole_check.If(check);
hole_check.Then();
- environment()->Push(BuildThrowReferenceError(variable));
+ environment()->Push(BuildThrowReferenceError(variable, bailout_id));
hole_check.Else();
environment()->Push(not_hole);
hole_check.End();
Unique<Name> name = MakeUnique(variable->name());
const Operator* op = javascript()->LoadNamed(name, contextual_mode);
Node* node = NewNode(op, global);
- PrepareFrameState(node, bailout_id, kPushOutput);
+ PrepareFrameState(node, bailout_id, OutputFrameStateCombine::Push());
return node;
}
case Variable::PARAMETER:
} else if (mode == LET || mode == CONST) {
// Perform check for uninitialized let/const variables.
if (value->op() == the_hole->op()) {
- value = BuildThrowReferenceError(variable);
+ value = BuildThrowReferenceError(variable, bailout_id);
} else if (value->opcode() == IrOpcode::kPhi) {
- value = BuildHoleCheckThrow(value, variable, value);
+ value = BuildHoleCheckThrow(value, variable, value, bailout_id);
}
}
return value;
value = BuildHoleCheckSilent(value, undefined, value);
} else if (mode == LET || mode == CONST) {
// Perform check for uninitialized let/const variables.
- value = BuildHoleCheckThrow(value, variable, value);
+ value = BuildHoleCheckThrow(value, variable, value, bailout_id);
}
return value;
}
: Runtime::kLoadLookupSlotNoReferenceError;
const Operator* op = javascript()->Runtime(function_id, 2);
Node* pair = NewNode(op, current_context(), name);
+ PrepareFrameState(pair, bailout_id, OutputFrameStateCombine::Push(1));
return NewNode(common()->Projection(0), pair);
}
}
}
-Node* AstGraphBuilder::BuildVariableDelete(Variable* variable) {
+Node* AstGraphBuilder::BuildVariableDelete(
+ Variable* variable, BailoutId bailout_id,
+ OutputFrameStateCombine state_combine) {
switch (variable->location()) {
case Variable::UNALLOCATED: {
// Global var, const, or let variable.
Node* global = BuildLoadGlobalObject();
Node* name = jsgraph()->Constant(variable->name());
const Operator* op = javascript()->DeleteProperty(strict_mode());
- return NewNode(op, global, name);
+ Node* result = NewNode(op, global, name);
+ PrepareFrameState(result, bailout_id, state_combine);
+ return result;
}
case Variable::PARAMETER:
case Variable::LOCAL:
// Dynamic lookup of context variable (anywhere in the chain).
Node* name = jsgraph()->Constant(variable->name());
const Operator* op = javascript()->Runtime(Runtime::kDeleteLookupSlot, 2);
- return NewNode(op, current_context(), name);
+ Node* result = NewNode(op, current_context(), name);
+ PrepareFrameState(result, bailout_id, state_combine);
+ return result;
}
}
UNREACHABLE();
// temporal dead zone of a let declared variable.
Node* current = environment()->Lookup(variable);
if (current->op() == the_hole->op()) {
- value = BuildThrowReferenceError(variable);
+ value = BuildThrowReferenceError(variable, bailout_id);
} else if (value->opcode() == IrOpcode::kPhi) {
- value = BuildHoleCheckThrow(current, variable, value);
+ value = BuildHoleCheckThrow(current, variable, value, bailout_id);
}
} else if (mode == CONST && op != Token::INIT_CONST) {
// All assignments to const variables are early errors.
const Operator* op =
javascript()->LoadContext(depth, variable->index(), false);
Node* current = NewNode(op, current_context());
- value = BuildHoleCheckThrow(current, variable, value);
+ value = BuildHoleCheckThrow(current, variable, value, bailout_id);
} else if (mode == CONST && op != Token::INIT_CONST) {
// All assignments to const variables are early errors.
UNREACHABLE();
// TODO(mstarzinger): Use Runtime::kInitializeLegacyConstLookupSlot for
// initializations of const declarations.
const Operator* op = javascript()->Runtime(Runtime::kStoreLookupSlot, 4);
- return NewNode(op, value, current_context(), name, strict);
+ Node* store = NewNode(op, value, current_context(), name, strict);
+ PrepareFrameState(store, bailout_id);
+ return store;
}
}
UNREACHABLE();
}
-Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable) {
+Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable,
+ BailoutId bailout_id) {
// TODO(mstarzinger): Should be unified with the VisitThrow implementation.
Node* variable_name = jsgraph()->Constant(variable->name());
const Operator* op = javascript()->Runtime(Runtime::kThrowReferenceError, 1);
- return NewNode(op, variable_name);
+ Node* call = NewNode(op, variable_name);
+ PrepareFrameState(call, bailout_id);
+ return call;
}
// Builders for variable load and assignment.
Node* BuildVariableAssignment(Variable* var, Node* value, Token::Value op,
BailoutId bailout_id);
- Node* BuildVariableDelete(Variable* var);
+ Node* BuildVariableDelete(Variable* var, BailoutId bailout_id,
+ OutputFrameStateCombine state_combine);
Node* BuildVariableLoad(Variable* var, BailoutId bailout_id,
ContextualMode mode = CONTEXTUAL);
Node* BuildToBoolean(Node* value);
// Builders for error reporting at runtime.
- Node* BuildThrowReferenceError(Variable* var);
+ Node* BuildThrowReferenceError(Variable* var, BailoutId bailout_id);
// Builders for dynamic hole-checks at runtime.
Node* BuildHoleCheckSilent(Node* value, Node* for_hole, Node* not_hole);
- Node* BuildHoleCheckThrow(Node* value, Variable* var, Node* not_hole);
+ Node* BuildHoleCheckThrow(Node* value, Variable* var, Node* not_hole,
+ BailoutId bailout_id);
// Builders for binary operations.
Node* BuildBinaryOp(Node* left, Node* right, Token::Value op);
void VisitForInAssignment(Expression* expr, Node* value);
// Builds deoptimization for a given node.
- void PrepareFrameState(Node* node, BailoutId ast_id,
- OutputFrameStateCombine combine = kIgnoreOutput);
+ void PrepareFrameState(
+ Node* node, BailoutId ast_id,
+ OutputFrameStateCombine combine = OutputFrameStateCombine::Ignore());
OutputFrameStateCombine StateCombineFromAstContext();
// Determines how to combine the frame state with the value
// that is about to be plugged into this AstContext.
OutputFrameStateCombine GetStateCombine() {
- return IsEffect() ? kIgnoreOutput : kPushOutput;
+ return IsEffect() ? OutputFrameStateCombine::Ignore()
+ : OutputFrameStateCombine::Push();
}
// Plug a node into this expression context. Call this function in tail
// because it is only used to get locals and arguments (by the debugger and
// f.arguments), and those are the same in the pre-call and post-call
// states.
- if (descriptor->state_combine() != kIgnoreOutput) {
- deopt_state_id =
- BuildTranslation(instr, -1, frame_state_offset, kIgnoreOutput);
+ if (!descriptor->state_combine().IsOutputIgnored()) {
+ deopt_state_id = BuildTranslation(instr, -1, frame_state_offset,
+ OutputFrameStateCombine::Ignore());
}
#if DEBUG
// Make sure all the values live in stack slots or they are immediates.
// (The values should not live in register because registers are clobbered
// by calls.)
- for (size_t i = 0; i < descriptor->size(); i++) {
+ for (size_t i = 0; i < descriptor->GetSize(); i++) {
InstructionOperand* op = instr->InputAt(frame_state_offset + 1 + i);
CHECK(op->IsStackSlot() || op->IsImmediate());
}
return code()->GetFrameStateDescriptor(state_id);
}
+static InstructionOperand* OperandForFrameState(
+ FrameStateDescriptor* descriptor, Instruction* instr,
+ size_t frame_state_offset, size_t index, OutputFrameStateCombine combine) {
+ DCHECK(index < descriptor->GetSize(combine));
+ switch (combine.kind()) {
+ case OutputFrameStateCombine::kPushOutput: {
+ DCHECK(combine.GetPushCount() <= instr->OutputCount());
+ size_t size_without_output =
+ descriptor->GetSize(OutputFrameStateCombine::Ignore());
+ // If the index is past the existing stack items, return the output.
+ if (index >= size_without_output) {
+ return instr->OutputAt(index - size_without_output);
+ }
+ break;
+ }
+ case OutputFrameStateCombine::kPokeAt:
+ size_t index_from_top =
+ descriptor->GetSize(combine) - 1 - combine.GetOffsetToPokeAt();
+ if (index >= index_from_top &&
+ index < index_from_top + instr->OutputCount()) {
+ return instr->OutputAt(index - index_from_top);
+ }
+ break;
+ }
+ return instr->InputAt(frame_state_offset + index);
+}
+
void CodeGenerator::BuildTranslationForFrameStateDescriptor(
FrameStateDescriptor* descriptor, Instruction* instr,
if (descriptor->outer_state() != NULL) {
BuildTranslationForFrameStateDescriptor(descriptor->outer_state(), instr,
translation, frame_state_offset,
- kIgnoreOutput);
+ OutputFrameStateCombine::Ignore());
}
int id = Translation::kSelfLiteralId;
case JS_FRAME:
translation->BeginJSFrame(
descriptor->bailout_id(), id,
- static_cast<unsigned int>(descriptor->GetHeight(state_combine)));
+ static_cast<unsigned int>(descriptor->GetSize(state_combine) -
+ descriptor->parameters_count()));
break;
case ARGUMENTS_ADAPTOR:
translation->BeginArgumentsAdaptorFrame(
}
frame_state_offset += descriptor->outer_state()->GetTotalSize();
- for (size_t i = 0; i < descriptor->size(); i++) {
- AddTranslationForOperand(
- translation, instr,
- instr->InputAt(static_cast<int>(frame_state_offset + i)));
- }
-
- switch (state_combine) {
- case kPushOutput:
- DCHECK(instr->OutputCount() == 1);
- AddTranslationForOperand(translation, instr, instr->OutputAt(0));
- break;
- case kIgnoreOutput:
- break;
+ for (size_t i = 0; i < descriptor->GetSize(state_combine); i++) {
+ InstructionOperand* op = OperandForFrameState(
+ descriptor, instr, frame_state_offset, i, state_combine);
+ AddTranslationForOperand(translation, instr, op);
}
}
1, 1, "Projection", index);
}
+
+OutputFrameStateCombine::OutputFrameStateCombine(CombineKind kind,
+ size_t parameter)
+ : kind_(kind), parameter_(parameter) {}
+
+// static
+OutputFrameStateCombine OutputFrameStateCombine::Ignore() {
+ return OutputFrameStateCombine(kPushOutput, 0);
+}
+
+
+// static
+OutputFrameStateCombine OutputFrameStateCombine::Push(size_t count) {
+ return OutputFrameStateCombine(kPushOutput, count);
+}
+
+
+// static
+OutputFrameStateCombine OutputFrameStateCombine::PokeAt(size_t index) {
+ return OutputFrameStateCombine(kPokeAt, index);
+}
+
+
+OutputFrameStateCombine::CombineKind OutputFrameStateCombine::kind() {
+ return kind_;
+}
+
+
+size_t OutputFrameStateCombine::GetPushCount() {
+ DCHECK(kind() == kPushOutput);
+ return parameter_;
+}
+
+
+size_t OutputFrameStateCombine::GetOffsetToPokeAt() {
+ DCHECK(kind() == kPokeAt);
+ return parameter_;
+}
+
+
+bool OutputFrameStateCombine::IsOutputIgnored() {
+ return kind() == kPushOutput && GetPushCount() == 0;
+}
+
} // namespace compiler
} // namespace internal
} // namespace v8
// Flag that describes how to combine the current environment with
// the output of a node to obtain a framestate for lazy bailout.
-enum OutputFrameStateCombine {
- kPushOutput, // Push the output on the expression stack.
- kIgnoreOutput // Use the frame state as-is.
+class OutputFrameStateCombine {
+ public:
+ enum CombineKind {
+ kPushOutput, // Push the output on the expression stack.
+ kPokeAt // Poke at the given environment location,
+ // counting from the top of the stack.
+ };
+
+ static OutputFrameStateCombine Ignore();
+ static OutputFrameStateCombine Push(size_t count = 1);
+ static OutputFrameStateCombine PokeAt(size_t index);
+
+ CombineKind kind();
+ size_t GetPushCount();
+ size_t GetOffsetToPokeAt();
+
+ bool IsOutputIgnored();
+
+ private:
+ OutputFrameStateCombine(CombineKind kind, size_t parameter);
+
+ CombineKind kind_;
+ size_t parameter_;
};
Node* context_dummy = m.Int32Constant(0);
Node* state_node = m.NewNode(
- m.common()->FrameState(JS_FRAME, bailout_id, kPushOutput), parameters,
- locals, stack, context_dummy, m.UndefinedConstant());
+ m.common()->FrameState(JS_FRAME, bailout_id,
+ OutputFrameStateCombine::Push()),
+ parameters, locals, stack, context_dummy, m.UndefinedConstant());
Node* call = m.CallJS0(function_node, receiver, context, state_node);
m.Return(call);
Node* context_sentinel = m.Int32Constant(0);
Node* frame_state_before = m.NewNode(
- m.common()->FrameState(JS_FRAME, bailout_id_before, kPushOutput),
+ m.common()->FrameState(JS_FRAME, bailout_id_before,
+ OutputFrameStateCombine::Push()),
parameters, locals, stack, context_sentinel, m.UndefinedConstant());
// Build the call.
FrameStateDescriptor* desc_before =
s.GetFrameStateDescriptor(deopt_id_before);
EXPECT_EQ(bailout_id_before, desc_before->bailout_id());
- EXPECT_EQ(kPushOutput, desc_before->state_combine());
+ EXPECT_EQ(OutputFrameStateCombine::kPushOutput,
+ desc_before->state_combine().kind());
EXPECT_EQ(1u, desc_before->parameters_count());
EXPECT_EQ(1u, desc_before->locals_count());
EXPECT_EQ(1u, desc_before->stack_count());
Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(63));
Node* locals = m.NewNode(m.common()->StateValues(1), m.Int32Constant(64));
Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(65));
- Node* frame_state_parent = m.NewNode(
- m.common()->FrameState(JS_FRAME, bailout_id_parent, kIgnoreOutput),
- parameters, locals, stack, context, m.UndefinedConstant());
+ Node* frame_state_parent =
+ m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_parent,
+ OutputFrameStateCombine::Ignore()),
+ parameters, locals, stack, context, m.UndefinedConstant());
Node* context2 = m.Int32Constant(46);
Node* parameters2 =
m.NewNode(m.common()->StateValues(1), m.Int32Constant(43));
Node* locals2 = m.NewNode(m.common()->StateValues(1), m.Int32Constant(44));
Node* stack2 = m.NewNode(m.common()->StateValues(1), m.Int32Constant(45));
- Node* frame_state_before = m.NewNode(
- m.common()->FrameState(JS_FRAME, bailout_id_before, kPushOutput),
- parameters2, locals2, stack2, context2, frame_state_parent);
+ Node* frame_state_before =
+ m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_before,
+ OutputFrameStateCombine::Push()),
+ parameters2, locals2, stack2, context2, frame_state_parent);
// Build the call.
Node* call = m.CallFunctionStub0(function_node, receiver, context2,
FrameStateDescriptor* outer_state() const { return outer_state_; }
MaybeHandle<JSFunction> jsfunction() const { return jsfunction_; }
- size_t size() const {
- return parameters_count_ + locals_count_ + stack_count_ +
- (HasContext() ? 1 : 0);
+ size_t GetSize(OutputFrameStateCombine combine =
+ OutputFrameStateCombine::Ignore()) const {
+ size_t size = parameters_count_ + locals_count_ + stack_count_ +
+ (HasContext() ? 1 : 0);
+ switch (combine.kind()) {
+ case OutputFrameStateCombine::kPushOutput:
+ size += combine.GetPushCount();
+ break;
+ case OutputFrameStateCombine::kPokeAt:
+ break;
+ }
+ return size;
}
size_t GetTotalSize() const {
size_t total_size = 0;
for (const FrameStateDescriptor* iter = this; iter != NULL;
iter = iter->outer_state_) {
- total_size += iter->size();
+ total_size += iter->GetSize();
}
return total_size;
}
- size_t GetHeight(OutputFrameStateCombine override) const {
- size_t height = size() - parameters_count();
- switch (override) {
- case kPushOutput:
- ++height;
- break;
- case kIgnoreOutput:
- break;
- }
- return height;
- }
-
size_t GetFrameCount() const {
size_t count = 0;
for (const FrameStateDescriptor* iter = this; iter != NULL;
int nargs) {
Callable callable =
CodeFactory::CallFunction(isolate(), nargs - 1, NO_CALL_FUNCTION_FLAGS);
- CallDescriptor* desc =
- linkage()->GetStubCallDescriptor(callable.descriptor(), nargs);
+ CallDescriptor* desc = linkage()->GetStubCallDescriptor(
+ callable.descriptor(), nargs, FlagsForNode(node));
// TODO(mstarzinger): Accessing the builtins object this way prevents sharing
// of code across native contexts. Fix this by loading from given context.
Handle<JSFunction> function(
void JSGenericLowering::LowerJSToNumber(Node* node) {
Callable callable = CodeFactory::ToNumber(isolate());
- ReplaceWithStubCall(node, callable, CallDescriptor::kNoFlags);
+ ReplaceWithStubCall(node, callable, FlagsForNode(node));
}
InstanceofStub::kArgsInRegisters);
InstanceofStub stub(isolate(), flags);
CallInterfaceDescriptor d = stub.GetCallInterfaceDescriptor();
- CallDescriptor* desc = linkage()->GetStubCallDescriptor(d, 0);
+ CallDescriptor* desc =
+ linkage()->GetStubCallDescriptor(d, 0, FlagsForNode(node));
Node* stub_code = CodeConstant(stub.GetCode());
PatchInsertInput(node, 0, stub_code);
PatchOperator(node, common()->Call(desc));
Node* JSInliner::CreateArgumentsAdaptorFrameState(JSCallFunctionAccessor* call,
Handle<JSFunction> jsfunction,
Zone* temp_zone) {
- const Operator* op =
- jsgraph_->common()->FrameState(FrameStateType::ARGUMENTS_ADAPTOR,
- BailoutId(-1), kIgnoreOutput, jsfunction);
+ const Operator* op = jsgraph_->common()->FrameState(
+ FrameStateType::ARGUMENTS_ADAPTOR, BailoutId(-1),
+ OutputFrameStateCombine::Ignore(), jsfunction);
const Operator* op0 = jsgraph_->common()->StateValues(0);
Node* node0 = jsgraph_->graph()->NewNode(op0);
NodeVector params(temp_zone);
// TODO(jarin) At the moment, we only add frame state for
// few chosen runtime functions.
switch (function) {
+ case Runtime::kApply:
+ case Runtime::kArrayBufferNeuter:
+ case Runtime::kArrayConcat:
+ case Runtime::kBasicJSONStringify:
+ case Runtime::kCheckExecutionState:
+ case Runtime::kCollectStackTrace:
+ case Runtime::kCompileLazy:
+ case Runtime::kCompileOptimized:
+ case Runtime::kCompileString:
case Runtime::kDebugBreak:
+ case Runtime::kDataViewSetInt8:
+ case Runtime::kDataViewSetUint8:
+ case Runtime::kDataViewSetInt16:
+ case Runtime::kDataViewSetUint16:
+ case Runtime::kDataViewSetInt32:
+ case Runtime::kDataViewSetUint32:
+ case Runtime::kDataViewSetFloat32:
+ case Runtime::kDataViewSetFloat64:
+ case Runtime::kDataViewGetInt8:
+ case Runtime::kDataViewGetUint8:
+ case Runtime::kDataViewGetInt16:
+ case Runtime::kDataViewGetUint16:
+ case Runtime::kDataViewGetInt32:
+ case Runtime::kDataViewGetUint32:
+ case Runtime::kDataViewGetFloat32:
+ case Runtime::kDataViewGetFloat64:
+ case Runtime::kDebugEvaluate:
case Runtime::kDebugGetLoadedScripts:
+ case Runtime::kDebugGetPropertyDetails:
+ case Runtime::kDebugPromiseRejectEvent:
+ case Runtime::kDebugPromiseEvent:
+ case Runtime::kDeleteProperty:
case Runtime::kDeoptimizeFunction:
+ case Runtime::kFunctionBindArguments:
+ case Runtime::kGetFrameCount:
+ case Runtime::kGetOwnProperty:
case Runtime::kInlineCallFunction:
+ case Runtime::kInlineDateField:
+ case Runtime::kInlineRegExpExec:
+ case Runtime::kLiveEditGatherCompileInfo:
+ case Runtime::kLoadLookupSlot:
+ case Runtime::kLoadLookupSlotNoReferenceError:
+ case Runtime::kMaterializeRegExpLiteral:
+ case Runtime::kNewObjectFromBound:
+ case Runtime::kObjectFreeze:
+ case Runtime::kParseJson:
case Runtime::kPrepareStep:
+ case Runtime::kPreventExtensions:
+ case Runtime::kRegExpCompile:
+ case Runtime::kRegExpExecMultiple:
+ case Runtime::kResolvePossiblyDirectEval:
+ // case Runtime::kSetPrototype:
case Runtime::kSetScriptBreakPoint:
case Runtime::kStackGuard:
- case Runtime::kCheckExecutionState:
- case Runtime::kDebugEvaluate:
- case Runtime::kCollectStackTrace:
+ case Runtime::kStoreLookupSlot:
+ case Runtime::kStringBuilderConcat:
+ case Runtime::kStringReplaceGlobalRegExpWithString:
+ case Runtime::kThrowReferenceError:
+ case Runtime::kThrow:
+ case Runtime::kTypedArraySetFastCases:
+ case Runtime::kTypedArrayInitializeFromArrayLike:
return true;
default:
return false;
// Compare operations
case IrOpcode::kJSEqual:
- case IrOpcode::kJSNotEqual:
- case IrOpcode::kJSLessThan:
case IrOpcode::kJSGreaterThan:
- case IrOpcode::kJSLessThanOrEqual:
case IrOpcode::kJSGreaterThanOrEqual:
+ case IrOpcode::kJSHasProperty:
+ case IrOpcode::kJSInstanceOf:
+ case IrOpcode::kJSLessThan:
+ case IrOpcode::kJSLessThanOrEqual:
+ case IrOpcode::kJSNotEqual:
// Binary operations
+ case IrOpcode::kJSAdd:
+ case IrOpcode::kJSBitwiseAnd:
case IrOpcode::kJSBitwiseOr:
case IrOpcode::kJSBitwiseXor:
- case IrOpcode::kJSBitwiseAnd:
+ case IrOpcode::kJSDivide:
+ case IrOpcode::kJSLoadNamed:
+ case IrOpcode::kJSLoadProperty:
+ case IrOpcode::kJSModulus:
+ case IrOpcode::kJSMultiply:
case IrOpcode::kJSShiftLeft:
case IrOpcode::kJSShiftRight:
case IrOpcode::kJSShiftRightLogical:
- case IrOpcode::kJSAdd:
- case IrOpcode::kJSSubtract:
- case IrOpcode::kJSMultiply:
- case IrOpcode::kJSDivide:
- case IrOpcode::kJSModulus:
- case IrOpcode::kJSLoadProperty:
- case IrOpcode::kJSStoreProperty:
- case IrOpcode::kJSLoadNamed:
case IrOpcode::kJSStoreNamed:
+ case IrOpcode::kJSStoreProperty:
+ case IrOpcode::kJSSubtract:
+
+ // Other
+ case IrOpcode::kJSDeleteProperty:
return true;
default:
// edx (receiver). Touch up the stack with the right values.
__ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
__ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
+
+ PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
}
// Record source position for debugger.
SetSourcePosition(expr->position());
__ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ push(eax); // Function.
__ push(edx); // Receiver.
+ PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the function
// and receiver and have the slow path jump around this code.
// v1 (receiver). Touch up the stack with the right values.
__ sw(v0, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ sw(v1, MemOperand(sp, arg_count * kPointerSize));
+
+ PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
}
// Record source position for debugger.
SetSourcePosition(expr->position());
__ Push(context_register(), a2);
__ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ Push(v0, v1); // Function, receiver.
+ PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the
// function and receiver and have the slow path jump around this
// v1 (receiver). Touch up the stack with the right values.
__ sd(v0, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ sd(v1, MemOperand(sp, arg_count * kPointerSize));
+
+ PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
}
// Record source position for debugger.
SetSourcePosition(expr->position());
__ Push(context_register(), a2);
__ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ Push(v0, v1); // Function, receiver.
+ PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the
// function and receiver and have the slow path jump around this
// rdx (receiver). Touch up the stack with the right values.
__ movp(Operand(rsp, (arg_count + 0) * kPointerSize), rdx);
__ movp(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
+
+ PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
}
// Record source position for debugger.
SetSourcePosition(expr->position());
__ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ Push(rax); // Function.
__ Push(rdx); // Receiver.
+ PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the function
// and receiver and have the slow path jump around this code.
// edx (receiver). Touch up the stack with the right values.
__ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
__ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
+
+ PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
}
// Record source position for debugger.
SetSourcePosition(expr->position());
__ CallRuntime(Runtime::kLoadLookupSlot, 2);
__ push(eax); // Function.
__ push(edx); // Receiver.
+ PrepareForBailoutForId(expr->EvalOrLookupId(), NO_REGISTERS);
// If fast case code has been generated, emit code to push the function
// and receiver and have the slow path jump around this code.
Node* stack = m.NewNode(common.StateValues(0));
Node* state_node = m.NewNode(
- common.FrameState(JS_FRAME, bailout_id, kIgnoreOutput), parameters,
- locals, stack, caller_context_node, m.UndefinedConstant());
+ common.FrameState(JS_FRAME, bailout_id,
+ OutputFrameStateCombine::Ignore()),
+ parameters, locals, stack, caller_context_node, m.UndefinedConstant());
Handle<Context> context(deopt_function->context(), CcTest::i_isolate());
Unique<Object> context_constant =
Node* stack = m.NewNode(common.StateValues(0));
Node* state_node = m.NewNode(
- common.FrameState(JS_FRAME, bailout_id, kIgnoreOutput), parameters,
- locals, stack, context_node, m.UndefinedConstant());
+ common.FrameState(JS_FRAME, bailout_id,
+ OutputFrameStateCombine::Ignore()),
+ parameters, locals, stack, context_node, m.UndefinedConstant());
m.CallRuntime1(Runtime::kDeoptimizeFunction, this_fun_node, context_node,
state_node);
Node* stack = graph.NewNode(common.StateValues(0));
Node* state_node =
- graph.NewNode(common.FrameState(JS_FRAME, BailoutId(0), kIgnoreOutput),
+ graph.NewNode(common.FrameState(JS_FRAME, BailoutId(0),
+ OutputFrameStateCombine::Ignore()),
parameters, locals, stack, context, UndefinedConstant());
return state_node;
// On MacOS X 10.7.5, this test needs a stack size of at least 788 kBytes.
// Flags: --stack-size=800
+// Flags: --turbo-deoptimization
// Test that we can make large object literals that work.
// Also test that we can attempt to make even larger object literals without
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// Flags: --expose-debug-as debug
+// Flags: --expose-debug-as debug --turbo-deoptimization
// Get the Debug object exposed from the debug context global object.
Debug = debug.Debug
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// Flags: --turbo-deoptimization
+
for (var i = 0; i < 10000; i++) {
try {
var object = { };
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// Flags: --turbo-deoptimization
+
function CheckStrictMode(code, exception) {
assertDoesNotThrow(code);
assertThrows("'use strict';\n" + code, exception);