| Index: src/x64/full-codegen-x64.cc
|
| ===================================================================
|
| --- src/x64/full-codegen-x64.cc (revision 6941)
|
| +++ src/x64/full-codegen-x64.cc (working copy)
|
| @@ -1,4 +1,4 @@
|
| -// Copyright 2010 the V8 project authors. All rights reserved.
|
| +// Copyright 2011 the V8 project authors. All rights reserved.
|
| // Redistribution and use in source and binary forms, with or without
|
| // modification, are permitted provided that the following conditions are
|
| // met:
|
| @@ -199,7 +199,7 @@
|
|
|
|
|
| void FullCodeGenerator::ClearAccumulator() {
|
| - __ xor_(rax, rax);
|
| + __ Set(rax, 0);
|
| }
|
|
|
|
|
| @@ -210,10 +210,17 @@
|
| __ j(above_equal, &ok);
|
| StackCheckStub stub;
|
| __ CallStub(&stub);
|
| + // Record a mapping of this PC offset to the OSR id. This is used to find
|
| + // the AST id from the unoptimized code in order to use it as a key into
|
| + // the deoptimization input data found in the optimized code.
|
| + RecordStackCheck(stmt->OsrEntryId());
|
| +
|
| __ bind(&ok);
|
| PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
|
| + // Record a mapping of the OSR id to this PC. This is used if the OSR
|
| + // entry becomes the target of a bailout. We don't expect it to be, but
|
| + // we want it to work if it is.
|
| PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
|
| - RecordStackCheck(stmt->OsrEntryId());
|
| }
|
|
|
|
|
| @@ -459,7 +466,10 @@
|
|
|
|
|
| void FullCodeGenerator::TestContext::Plug(bool flag) const {
|
| - codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
|
| + codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
|
| + true,
|
| + true_label_,
|
| + false_label_);
|
| if (flag) {
|
| if (true_label_ != fall_through_) __ jmp(true_label_);
|
| } else {
|
| @@ -555,6 +565,25 @@
|
| bool should_normalize,
|
| Label* if_true,
|
| Label* if_false) {
|
| + // Only prepare for bailouts before splits if we're in a test
|
| + // context. Otherwise, we let the Visit function deal with the
|
| + // preparation to avoid preparing with the same AST id twice.
|
| + if (!context()->IsTest() || !info_->IsOptimizable()) return;
|
| +
|
| + NearLabel skip;
|
| + if (should_normalize) __ jmp(&skip);
|
| +
|
| + ForwardBailoutStack* current = forward_bailout_stack_;
|
| + while (current != NULL) {
|
| + PrepareForBailout(current->expr(), state);
|
| + current = current->parent();
|
| + }
|
| +
|
| + if (should_normalize) {
|
| + __ CompareRoot(rax, Heap::kTrueValueRootIndex);
|
| + Split(equal, if_true, if_false, NULL);
|
| + __ bind(&skip);
|
| + }
|
| }
|
|
|
|
|
| @@ -670,8 +699,10 @@
|
| Comment cmnt(masm_, "[ SwitchStatement");
|
| Breakable nested_statement(this, stmt);
|
| SetStatementPosition(stmt);
|
| +
|
| // Keep the switch value on the stack until a case matches.
|
| VisitForStackValue(stmt->tag());
|
| + PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
|
|
|
| ZoneList<CaseClause*>* clauses = stmt->cases();
|
| CaseClause* default_clause = NULL; // Can occur anywhere in the list.
|
| @@ -736,6 +767,7 @@
|
| }
|
|
|
| __ bind(nested_statement.break_target());
|
| + PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
|
| }
|
|
|
|
|
| @@ -1232,6 +1264,7 @@
|
| Handle<Code> ic(isolate()->builtins()->builtin(
|
| Builtins::StoreIC_Initialize));
|
| EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
| + PrepareForBailoutForId(key->id(), NO_REGISTERS);
|
| }
|
| break;
|
| }
|
| @@ -1320,6 +1353,8 @@
|
|
|
| // Update the write barrier for the array store.
|
| __ RecordWrite(rbx, offset, result_register(), rcx);
|
| +
|
| + PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
|
| }
|
|
|
| if (result_saved) {
|
| @@ -1364,17 +1399,34 @@
|
| VisitForStackValue(property->obj());
|
| }
|
| break;
|
| - case KEYED_PROPERTY:
|
| + case KEYED_PROPERTY: {
|
| if (expr->is_compound()) {
|
| - VisitForStackValue(property->obj());
|
| - VisitForAccumulatorValue(property->key());
|
| + if (property->is_arguments_access()) {
|
| + VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
|
| + MemOperand slot_operand =
|
| + EmitSlotSearch(obj_proxy->var()->AsSlot(), rcx);
|
| + __ push(slot_operand);
|
| + __ Move(rax, property->key()->AsLiteral()->handle());
|
| + } else {
|
| + VisitForStackValue(property->obj());
|
| + VisitForAccumulatorValue(property->key());
|
| + }
|
| __ movq(rdx, Operand(rsp, 0));
|
| __ push(rax);
|
| } else {
|
| - VisitForStackValue(property->obj());
|
| - VisitForStackValue(property->key());
|
| + if (property->is_arguments_access()) {
|
| + VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
|
| + MemOperand slot_operand =
|
| + EmitSlotSearch(obj_proxy->var()->AsSlot(), rcx);
|
| + __ push(slot_operand);
|
| + __ Push(property->key()->AsLiteral()->handle());
|
| + } else {
|
| + VisitForStackValue(property->obj());
|
| + VisitForStackValue(property->key());
|
| + }
|
| }
|
| break;
|
| + }
|
| }
|
|
|
| if (expr->is_compound()) {
|
| @@ -1392,6 +1444,12 @@
|
| }
|
| }
|
|
|
| + // For property compound assignments we need another deoptimization
|
| + // point after the property load.
|
| + if (property != NULL) {
|
| + PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
|
| + }
|
| +
|
| Token::Value op = expr->binary_op();
|
| ConstantOperand constant = ShouldInlineSmiCase(op)
|
| ? GetConstantOperand(op, expr->target(), expr->value())
|
| @@ -1417,6 +1475,8 @@
|
| } else {
|
| EmitBinaryOp(op, mode);
|
| }
|
| + // Deoptimization point in case the binary operation may have side effects.
|
| + PrepareForBailout(expr->binary_operation(), TOS_REG);
|
| } else {
|
| VisitForAccumulatorValue(expr->value());
|
| }
|
| @@ -1429,6 +1489,7 @@
|
| case VARIABLE:
|
| EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
|
| expr->op());
|
| + PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
|
| context()->Plug(rax);
|
| break;
|
| case NAMED_PROPERTY:
|
| @@ -1540,7 +1601,7 @@
|
| }
|
|
|
|
|
| -void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_id) {
|
| +void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
|
| // Invalid left-hand sides are rewritten to have a 'throw
|
| // ReferenceError' on the left-hand side.
|
| if (!expr->IsValidLeftHandSide()) {
|
| @@ -1590,6 +1651,7 @@
|
| break;
|
| }
|
| }
|
| + PrepareForBailoutForId(bailout_ast_id, TOS_REG);
|
| context()->Plug(rax);
|
| }
|
|
|
| @@ -1703,6 +1765,7 @@
|
| __ pop(rax);
|
| __ Drop(1);
|
| }
|
| + PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
|
| context()->Plug(rax);
|
| }
|
|
|
| @@ -1742,6 +1805,7 @@
|
| __ pop(rax);
|
| }
|
|
|
| + PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
|
| context()->Plug(rax);
|
| }
|
|
|
| @@ -1783,6 +1847,7 @@
|
| Handle<Code> ic =
|
| ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop);
|
| EmitCallIC(ic, mode);
|
| + RecordJSReturnSite(expr);
|
| // Restore context register.
|
| __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
|
| context()->Plug(rax);
|
| @@ -1817,6 +1882,7 @@
|
| ISOLATE->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop);
|
| __ movq(rcx, Operand(rsp, (arg_count + 1) * kPointerSize)); // Key.
|
| EmitCallIC(ic, mode);
|
| + RecordJSReturnSite(expr);
|
| // Restore context register.
|
| __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
|
| context()->DropAndPlug(1, rax); // Drop the key still on the stack.
|
| @@ -1837,6 +1903,7 @@
|
| InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
| CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
|
| __ CallStub(&stub);
|
| + RecordJSReturnSite(expr);
|
| // Restore context register.
|
| __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
|
| // Discard the function left on TOS.
|
| @@ -1845,6 +1912,12 @@
|
|
|
|
|
| void FullCodeGenerator::VisitCall(Call* expr) {
|
| +#ifdef DEBUG
|
| + // We want to verify that RecordJSReturnSite gets called on all paths
|
| + // through this function. Avoid early returns.
|
| + expr->return_is_recorded_ = false;
|
| +#endif
|
| +
|
| Comment cmnt(masm_, "[ Call");
|
| Expression* fun = expr->expression();
|
| Variable* var = fun->AsVariableProxy()->AsVariable();
|
| @@ -1852,7 +1925,7 @@
|
| if (var != NULL && var->is_possibly_eval()) {
|
| // In a call to eval, we first call %ResolvePossiblyDirectEval to
|
| // resolve the function we need to call and the receiver of the
|
| - // call. The we call the resolved function using the given
|
| + // call. Then we call the resolved function using the given
|
| // arguments.
|
| ZoneList<Expression*>* args = expr->arguments();
|
| int arg_count = args->length();
|
| @@ -1889,6 +1962,7 @@
|
| InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
| CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
|
| __ CallStub(&stub);
|
| + RecordJSReturnSite(expr);
|
| // Restore context register.
|
| __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
|
| context()->DropAndPlug(1, rax);
|
| @@ -1911,32 +1985,31 @@
|
| &done);
|
|
|
| __ bind(&slow);
|
| - // Call the runtime to find the function to call (returned in rax)
|
| - // and the object holding it (returned in rdx).
|
| - __ push(context_register());
|
| - __ Push(var->name());
|
| - __ CallRuntime(Runtime::kLoadContextSlot, 2);
|
| - __ push(rax); // Function.
|
| - __ push(rdx); // Receiver.
|
| + }
|
| + // Call the runtime to find the function to call (returned in rax)
|
| + // and the object holding it (returned in rdx).
|
| + __ push(context_register());
|
| + __ Push(var->name());
|
| + __ CallRuntime(Runtime::kLoadContextSlot, 2);
|
| + __ push(rax); // Function.
|
| + __ push(rdx); // Receiver.
|
|
|
| - // If fast case code has been generated, emit code to push the
|
| - // function and receiver and have the slow path jump around this
|
| - // code.
|
| - if (done.is_linked()) {
|
| - NearLabel call;
|
| - __ jmp(&call);
|
| - __ bind(&done);
|
| - // Push function.
|
| - __ push(rax);
|
| - // Push global receiver.
|
| + // If fast case code has been generated, emit code to push the
|
| + // function and receiver and have the slow path jump around this
|
| + // code.
|
| + if (done.is_linked()) {
|
| + NearLabel call;
|
| + __ jmp(&call);
|
| + __ bind(&done);
|
| + // Push function.
|
| + __ push(rax);
|
| + // Push global receiver.
|
| __ movq(rbx, GlobalObjectOperand());
|
| __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
|
| __ bind(&call);
|
| - }
|
| }
|
|
|
| EmitCallWithStub(expr);
|
| -
|
| } else if (fun->AsProperty() != NULL) {
|
| // Call to an object property.
|
| Property* prop = fun->AsProperty();
|
| @@ -1950,25 +2023,24 @@
|
| } else {
|
| // Call to a keyed property.
|
| // For a synthetic property use keyed load IC followed by function call,
|
| - // for a regular property use KeyedCallIC.
|
| + // for a regular property use keyed EmitCallIC.
|
| { PreservePositionScope scope(masm()->positions_recorder());
|
| VisitForStackValue(prop->obj());
|
| }
|
| if (prop->is_synthetic()) {
|
| { PreservePositionScope scope(masm()->positions_recorder());
|
| VisitForAccumulatorValue(prop->key());
|
| - __ movq(rdx, Operand(rsp, 0));
|
| }
|
| // Record source code position for IC call.
|
| SetSourcePosition(prop->position());
|
| + __ pop(rdx); // We do not need to keep the receiver.
|
| +
|
| Handle<Code> ic(isolate()->builtins()->builtin(
|
| Builtins::KeyedLoadIC_Initialize));
|
| EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
| - // Pop receiver.
|
| - __ pop(rbx);
|
| // Push result (function).
|
| __ push(rax);
|
| - // Push receiver object on stack.
|
| + // Push Global receiver.
|
| __ movq(rcx, GlobalObjectOperand());
|
| __ push(FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset));
|
| EmitCallWithStub(expr);
|
| @@ -1979,7 +2051,7 @@
|
| } else {
|
| // Call to some other expression. If the expression is an anonymous
|
| // function literal not called in a loop, mark it as one that should
|
| - // also use the fast code generator.
|
| + // also use the full code generator.
|
| FunctionLiteral* lit = fun->AsFunctionLiteral();
|
| if (lit != NULL &&
|
| lit->name()->Equals(isolate()->heap()->empty_string()) &&
|
| @@ -1995,6 +2067,11 @@
|
| // Emit function call.
|
| EmitCallWithStub(expr);
|
| }
|
| +
|
| +#ifdef DEBUG
|
| + // RecordJSReturnSite should have been called.
|
| + ASSERT(expr->return_is_recorded_);
|
| +#endif
|
| }
|
|
|
|
|
| @@ -2043,6 +2120,7 @@
|
| context()->PrepareTest(&materialize_true, &materialize_false,
|
| &if_true, &if_false, &fall_through);
|
|
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| __ JumpIfSmi(rax, if_true);
|
| __ jmp(if_false);
|
|
|
| @@ -2062,6 +2140,7 @@
|
| context()->PrepareTest(&materialize_true, &materialize_false,
|
| &if_true, &if_false, &fall_through);
|
|
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| Condition non_negative_smi = masm()->CheckNonNegativeSmi(rax);
|
| Split(non_negative_smi, if_true, if_false, fall_through);
|
|
|
| @@ -2093,6 +2172,7 @@
|
| __ cmpq(rbx, Immediate(FIRST_JS_OBJECT_TYPE));
|
| __ j(below, if_false);
|
| __ cmpq(rbx, Immediate(LAST_JS_OBJECT_TYPE));
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| Split(below_equal, if_true, if_false, fall_through);
|
|
|
| context()->Plug(if_true, if_false);
|
| @@ -2113,6 +2193,7 @@
|
|
|
| __ JumpIfSmi(rax, if_false);
|
| __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx);
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| Split(above_equal, if_true, if_false, fall_through);
|
|
|
| context()->Plug(if_true, if_false);
|
| @@ -2135,6 +2216,7 @@
|
| __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
|
| __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
|
| Immediate(1 << Map::kIsUndetectable));
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| Split(not_zero, if_true, if_false, fall_through);
|
|
|
| context()->Plug(if_true, if_false);
|
| @@ -2157,6 +2239,7 @@
|
| // Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only
|
| // used in a few functions in runtime.js which should not normally be hit by
|
| // this compiler.
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| __ jmp(if_false);
|
| context()->Plug(if_true, if_false);
|
| }
|
| @@ -2176,6 +2259,7 @@
|
|
|
| __ JumpIfSmi(rax, if_false);
|
| __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| Split(equal, if_true, if_false, fall_through);
|
|
|
| context()->Plug(if_true, if_false);
|
| @@ -2196,6 +2280,7 @@
|
|
|
| __ JumpIfSmi(rax, if_false);
|
| __ CmpObjectType(rax, JS_ARRAY_TYPE, rbx);
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| Split(equal, if_true, if_false, fall_through);
|
|
|
| context()->Plug(if_true, if_false);
|
| @@ -2216,6 +2301,7 @@
|
|
|
| __ JumpIfSmi(rax, if_false);
|
| __ CmpObjectType(rax, JS_REGEXP_TYPE, rbx);
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| Split(equal, if_true, if_false, fall_through);
|
|
|
| context()->Plug(if_true, if_false);
|
| @@ -2247,6 +2333,7 @@
|
| __ bind(&check_frame_marker);
|
| __ SmiCompare(Operand(rax, StandardFrameConstants::kMarkerOffset),
|
| Smi::FromInt(StackFrame::CONSTRUCT));
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| Split(equal, if_true, if_false, fall_through);
|
|
|
| context()->Plug(if_true, if_false);
|
| @@ -2269,6 +2356,7 @@
|
|
|
| __ pop(rbx);
|
| __ cmpq(rax, rbx);
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| Split(equal, if_true, if_false, fall_through);
|
|
|
| context()->Plug(if_true, if_false);
|
| @@ -2842,6 +2930,7 @@
|
|
|
| __ testl(FieldOperand(rax, String::kHashFieldOffset),
|
| Immediate(String::kContainsCachedArrayIndexMask));
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| __ j(zero, if_true);
|
| __ jmp(if_false);
|
|
|
| @@ -2964,6 +3053,7 @@
|
| // Notice that the labels are swapped.
|
| context()->PrepareTest(&materialize_true, &materialize_false,
|
| &if_false, &if_true, &fall_through);
|
| + if (context()->IsTest()) ForwardBailoutToChild(expr);
|
| VisitForControl(expr->expression(), if_true, if_false, fall_through);
|
| context()->Plug(if_false, if_true); // Labels swapped.
|
| break;
|
| @@ -3077,14 +3167,26 @@
|
| __ push(rax); // Copy of receiver, needed for later store.
|
| EmitNamedPropertyLoad(prop);
|
| } else {
|
| - VisitForStackValue(prop->obj());
|
| - VisitForAccumulatorValue(prop->key());
|
| + if (prop->is_arguments_access()) {
|
| + VariableProxy* obj_proxy = prop->obj()->AsVariableProxy();
|
| + MemOperand slot_operand =
|
| + EmitSlotSearch(obj_proxy->var()->AsSlot(), rcx);
|
| + __ push(slot_operand);
|
| + __ Move(rax, prop->key()->AsLiteral()->handle());
|
| + } else {
|
| + VisitForStackValue(prop->obj());
|
| + VisitForAccumulatorValue(prop->key());
|
| + }
|
| __ movq(rdx, Operand(rsp, 0)); // Leave receiver on stack
|
| __ push(rax); // Copy of key, needed for later store.
|
| EmitKeyedPropertyLoad(prop);
|
| }
|
| }
|
|
|
| + // We need a second deoptimization point after loading the value
|
| + // in case evaluating the property load my have a side effect.
|
| + PrepareForBailout(expr->increment(), TOS_REG);
|
| +
|
| // Call ToNumber only if operand is not a smi.
|
| NearLabel no_conversion;
|
| Condition is_smi;
|
| @@ -3154,6 +3256,7 @@
|
| { EffectContext context(this);
|
| EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
|
| Token::ASSIGN);
|
| + PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
|
| context.Plug(rax);
|
| }
|
| // For all contexts except kEffect: We have the result on
|
| @@ -3165,6 +3268,7 @@
|
| // Perform the assignment as if via '='.
|
| EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
|
| Token::ASSIGN);
|
| + PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
|
| context()->Plug(rax);
|
| }
|
| break;
|
| @@ -3174,6 +3278,7 @@
|
| Handle<Code> ic(isolate()->builtins()->builtin(
|
| Builtins::StoreIC_Initialize));
|
| EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
| + PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
|
| if (expr->is_postfix()) {
|
| if (!context()->IsEffect()) {
|
| context()->PlugTOS();
|
| @@ -3189,6 +3294,7 @@
|
| Handle<Code> ic(isolate()->builtins()->builtin(
|
| Builtins::KeyedStoreIC_Initialize));
|
| EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
| + PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
|
| if (expr->is_postfix()) {
|
| if (!context()->IsEffect()) {
|
| context()->PlugTOS();
|
| @@ -3216,6 +3322,7 @@
|
| // Use a regular load, not a contextual load, to avoid a reference
|
| // error.
|
| EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
| + PrepareForBailout(expr, TOS_REG);
|
| context()->Plug(rax);
|
| } else if (proxy != NULL &&
|
| proxy->var()->AsSlot() != NULL &&
|
| @@ -3231,12 +3338,13 @@
|
| __ push(rsi);
|
| __ Push(proxy->name());
|
| __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
|
| + PrepareForBailout(expr, TOS_REG);
|
| __ bind(&done);
|
|
|
| context()->Plug(rax);
|
| } else {
|
| // This expression cannot throw a reference error at the top level.
|
| - Visit(expr);
|
| + context()->HandleExpression(expr);
|
| }
|
| }
|
|
|
| @@ -3261,6 +3369,7 @@
|
| { AccumulatorValueContext context(this);
|
| VisitForTypeofValue(left_unary->expression());
|
| }
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
|
|
| if (check->Equals(isolate()->heap()->number_symbol())) {
|
| Condition is_smi = masm_->CheckSmi(rax);
|
| @@ -3354,6 +3463,7 @@
|
| case Token::IN:
|
| VisitForStackValue(expr->right());
|
| __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
|
| + PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
|
| __ CompareRoot(rax, Heap::kTrueValueRootIndex);
|
| Split(equal, if_true, if_false, fall_through);
|
| break;
|
| @@ -3362,6 +3472,7 @@
|
| VisitForStackValue(expr->right());
|
| InstanceofStub stub(InstanceofStub::kNoFlags);
|
| __ CallStub(&stub);
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| __ testq(rax, rax);
|
| // The stub returns 0 for true.
|
| Split(zero, if_true, if_false, fall_through);
|
| @@ -3420,6 +3531,8 @@
|
| : NO_COMPARE_FLAGS;
|
| CompareStub stub(cc, strict, flags);
|
| __ CallStub(&stub);
|
| +
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| __ testq(rax, rax);
|
| Split(cc, if_true, if_false, fall_through);
|
| }
|
| @@ -3441,6 +3554,7 @@
|
| &if_true, &if_false, &fall_through);
|
|
|
| VisitForAccumulatorValue(expr->expression());
|
| + PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
|
| __ CompareRoot(rax, Heap::kNullValueRootIndex);
|
| if (expr->is_strict()) {
|
| Split(equal, if_true, if_false, fall_through);
|
|
|