| Index: src/ia32/full-codegen-ia32.cc
|
| diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
|
| index 07afba6c80d7ad264907a42904c29cc3689aac32..74e62296d41fc4bd97568dc8040669ad32fad4d3 100644
|
| --- a/src/ia32/full-codegen-ia32.cc
|
| +++ b/src/ia32/full-codegen-ia32.cc
|
| @@ -165,7 +165,7 @@ void FullCodeGenerator::Generate() {
|
| // Generators allocate locals, if any, in context slots.
|
| ASSERT(!info->function()->is_generator() || locals_count == 0);
|
| if (locals_count == 1) {
|
| - __ push(Immediate(isolate()->factory()->undefined_value()));
|
| + AsmPushHandle(isolate()->factory()->undefined_value());
|
| } else if (locals_count > 1) {
|
| if (locals_count >= 128) {
|
| EmitStackCheck(masm_, locals_count, ecx);
|
| @@ -189,6 +189,7 @@ void FullCodeGenerator::Generate() {
|
| for (int i = 0; i < remaining; i++) {
|
| __ push(eax);
|
| }
|
| + UpdateStackHeight(locals_count);
|
| }
|
| }
|
|
|
| @@ -200,15 +201,15 @@ void FullCodeGenerator::Generate() {
|
| Comment cmnt(masm_, "[ Allocate context");
|
| // Argument to NewContext is the function, which is still in edi.
|
| if (FLAG_harmony_scoping && info->scope()->is_global_scope()) {
|
| - __ push(edi);
|
| - __ Push(info->scope()->GetScopeInfo());
|
| - __ CallRuntime(Runtime::kHiddenNewGlobalContext, 2);
|
| + AsmPush(edi);
|
| + AsmPushHandle(info->scope()->GetScopeInfo());
|
| + AsmCallRuntime(Runtime::kHiddenNewGlobalContext, 2);
|
| } else if (heap_slots <= FastNewContextStub::kMaximumSlots) {
|
| FastNewContextStub stub(isolate(), heap_slots);
|
| __ CallStub(&stub);
|
| } else {
|
| - __ push(edi);
|
| - __ CallRuntime(Runtime::kHiddenNewFunctionContext, 1);
|
| + AsmPush(edi);
|
| + AsmCallRuntime(Runtime::kHiddenNewFunctionContext, 1);
|
| }
|
| function_in_register = false;
|
| // Context is returned in eax. It replaces the context passed to us.
|
| @@ -243,17 +244,17 @@ void FullCodeGenerator::Generate() {
|
| // Function uses arguments object.
|
| Comment cmnt(masm_, "[ Allocate arguments object");
|
| if (function_in_register) {
|
| - __ push(edi);
|
| + AsmPush(edi);
|
| } else {
|
| - __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
|
| + AsmPush(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
|
| }
|
| // Receiver is just before the parameters on the caller's stack.
|
| int num_parameters = info->scope()->num_parameters();
|
| int offset = num_parameters * kPointerSize;
|
| __ lea(edx,
|
| Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset));
|
| - __ push(edx);
|
| - __ push(Immediate(Smi::FromInt(num_parameters)));
|
| + AsmPush(edx);
|
| + AsmPushSmi(Smi::FromInt(num_parameters));
|
| // Arguments to ArgumentsAccessStub:
|
| // function, receiver address, parameter count.
|
| // The stub will rewrite receiver and parameter count if the previous
|
| @@ -267,13 +268,13 @@ void FullCodeGenerator::Generate() {
|
| type = ArgumentsAccessStub::NEW_SLOPPY_FAST;
|
| }
|
| ArgumentsAccessStub stub(isolate(), type);
|
| - __ CallStub(&stub);
|
| + AsmCallStub(&stub, 3);
|
|
|
| SetVar(arguments, eax, ebx, edx);
|
| }
|
|
|
| if (FLAG_trace) {
|
| - __ CallRuntime(Runtime::kTraceEnter, 0);
|
| + AsmCallRuntime(Runtime::kTraceEnter, 0);
|
| }
|
|
|
| // Visit the declarations and body unless there is an illegal
|
| @@ -375,8 +376,8 @@ void FullCodeGenerator::EmitReturnSequence() {
|
| // Common return label
|
| __ bind(&return_label_);
|
| if (FLAG_trace) {
|
| - __ push(eax);
|
| - __ CallRuntime(Runtime::kTraceExit, 1);
|
| + AsmPush(eax);
|
| + AsmCallRuntime(Runtime::kTraceExit, 1);
|
| }
|
| // Pretend that the exit is a backwards jump to the entry.
|
| int weight = 1;
|
| @@ -390,10 +391,10 @@ void FullCodeGenerator::EmitReturnSequence() {
|
| EmitProfilingCounterDecrement(weight);
|
| Label ok;
|
| __ j(positive, &ok, Label::kNear);
|
| - __ push(eax);
|
| + AsmPush(eax);
|
| __ call(isolate()->builtins()->InterruptCheck(),
|
| RelocInfo::CODE_TARGET);
|
| - __ pop(eax);
|
| + AsmPop(eax);
|
| EmitProfilingCounterReset();
|
| __ bind(&ok);
|
| #ifdef DEBUG
|
| @@ -435,7 +436,7 @@ void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
|
| ASSERT(var->IsStackAllocated() || var->IsContextSlot());
|
| MemOperand operand = codegen()->VarOperand(var, result_register());
|
| // Memory operands can be pushed directly.
|
| - __ push(operand);
|
| + codegen()->AsmPush(operand);
|
| }
|
|
|
|
|
| @@ -486,8 +487,9 @@ void FullCodeGenerator::AccumulatorValueContext::Plug(
|
| void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
|
| if (lit->IsSmi()) {
|
| __ SafePush(Immediate(lit));
|
| + codegen()->UpdateStackHeight(1);
|
| } else {
|
| - __ push(Immediate(lit));
|
| + codegen()->AsmPushHandle(lit);
|
| }
|
| }
|
|
|
| @@ -525,7 +527,7 @@ void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
|
| void FullCodeGenerator::EffectContext::DropAndPlug(int count,
|
| Register reg) const {
|
| ASSERT(count > 0);
|
| - __ Drop(count);
|
| + codegen()->AsmDrop(count);
|
| }
|
|
|
|
|
| @@ -533,7 +535,7 @@ void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
|
| int count,
|
| Register reg) const {
|
| ASSERT(count > 0);
|
| - __ Drop(count);
|
| + codegen()->AsmDrop(count);
|
| __ Move(result_register(), reg);
|
| }
|
|
|
| @@ -541,7 +543,7 @@ void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
|
| void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
|
| Register reg) const {
|
| ASSERT(count > 0);
|
| - if (count > 1) __ Drop(count - 1);
|
| + if (count > 1) codegen()->AsmDrop(count - 1);
|
| __ mov(Operand(esp, 0), reg);
|
| }
|
|
|
| @@ -550,7 +552,7 @@ void FullCodeGenerator::TestContext::DropAndPlug(int count,
|
| Register reg) const {
|
| ASSERT(count > 0);
|
| // For simplicity we always test the accumulator register.
|
| - __ Drop(count);
|
| + codegen()->AsmDrop(count);
|
| __ Move(result_register(), reg);
|
| codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
|
| codegen()->DoTest(this);
|
| @@ -580,12 +582,14 @@ void FullCodeGenerator::AccumulatorValueContext::Plug(
|
| void FullCodeGenerator::StackValueContext::Plug(
|
| Label* materialize_true,
|
| Label* materialize_false) const {
|
| + StackHeightWrapper stack_height = codegen()->CurrentStackHeight();
|
| Label done;
|
| __ bind(materialize_true);
|
| - __ push(Immediate(isolate()->factory()->true_value()));
|
| + codegen()->AsmPushHandle(isolate()->factory()->true_value());
|
| __ jmp(&done, Label::kNear);
|
| __ bind(materialize_false);
|
| - __ push(Immediate(isolate()->factory()->false_value()));
|
| + codegen()->SetStackHeight(stack_height);
|
| + codegen()->AsmPushHandle(isolate()->factory()->false_value());
|
| __ bind(&done);
|
| }
|
|
|
| @@ -613,7 +617,7 @@ void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
|
| Handle<Object> value = flag
|
| ? isolate()->factory()->true_value()
|
| : isolate()->factory()->false_value();
|
| - __ push(Immediate(value));
|
| + codegen()->AsmPushHandle(value);
|
| }
|
|
|
|
|
| @@ -783,23 +787,23 @@ void FullCodeGenerator::VisitVariableDeclaration(
|
|
|
| case Variable::LOOKUP: {
|
| Comment cmnt(masm_, "[ VariableDeclaration");
|
| - __ push(esi);
|
| - __ push(Immediate(variable->name()));
|
| + AsmPush(esi);
|
| + AsmPushHandle(variable->name());
|
| // VariableDeclaration nodes are always introduced in one of four modes.
|
| ASSERT(IsDeclaredVariableMode(mode));
|
| PropertyAttributes attr =
|
| IsImmutableVariableMode(mode) ? READ_ONLY : NONE;
|
| - __ push(Immediate(Smi::FromInt(attr)));
|
| + AsmPushSmi(Smi::FromInt(attr));
|
| // Push initial value, if any.
|
| // Note: For variables we must not push an initial value (such as
|
| // 'undefined') because we may have a (legal) redeclaration and we
|
| // must not destroy the current value.
|
| if (hole_init) {
|
| - __ push(Immediate(isolate()->factory()->the_hole_value()));
|
| + AsmPushHandle(isolate()->factory()->the_hole_value());
|
| } else {
|
| - __ push(Immediate(Smi::FromInt(0))); // Indicates no initial value.
|
| + AsmPushSmi(Smi::FromInt(0)); // Indicates no initial value.
|
| }
|
| - __ CallRuntime(Runtime::kHiddenDeclareContextSlot, 4);
|
| + AsmCallRuntime(Runtime::kHiddenDeclareContextSlot, 4);
|
| break;
|
| }
|
| }
|
| @@ -848,11 +852,11 @@ void FullCodeGenerator::VisitFunctionDeclaration(
|
|
|
| case Variable::LOOKUP: {
|
| Comment cmnt(masm_, "[ FunctionDeclaration");
|
| - __ push(esi);
|
| - __ push(Immediate(variable->name()));
|
| - __ push(Immediate(Smi::FromInt(NONE)));
|
| + AsmPush(esi);
|
| + AsmPushHandle(variable->name());
|
| + AsmPushSmi(Smi::FromInt(NONE));
|
| VisitForStackValue(declaration->fun());
|
| - __ CallRuntime(Runtime::kHiddenDeclareContextSlot, 4);
|
| + AsmCallRuntime(Runtime::kHiddenDeclareContextSlot, 4);
|
| break;
|
| }
|
| }
|
| @@ -919,18 +923,18 @@ void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) {
|
|
|
| void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
|
| // Call the runtime to declare the globals.
|
| - __ push(esi); // The context is the first argument.
|
| - __ Push(pairs);
|
| - __ Push(Smi::FromInt(DeclareGlobalsFlags()));
|
| - __ CallRuntime(Runtime::kHiddenDeclareGlobals, 3);
|
| + AsmPush(esi); // The context is the first argument.
|
| + AsmPushHandle(pairs);
|
| + AsmPushSmi(Smi::FromInt(DeclareGlobalsFlags()));
|
| + AsmCallRuntime(Runtime::kHiddenDeclareGlobals, 3);
|
| // Return value is ignored.
|
| }
|
|
|
|
|
| void FullCodeGenerator::DeclareModules(Handle<FixedArray> descriptions) {
|
| // Call the runtime to declare the modules.
|
| - __ Push(descriptions);
|
| - __ CallRuntime(Runtime::kHiddenDeclareModules, 1);
|
| + AsmPushHandle(descriptions);
|
| + AsmCallRuntime(Runtime::kHiddenDeclareModules, 1);
|
| // Return value is ignored.
|
| }
|
|
|
| @@ -947,6 +951,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
|
| ZoneList<CaseClause*>* clauses = stmt->cases();
|
| CaseClause* default_clause = NULL; // Can occur anywhere in the list.
|
|
|
| + StackHeightWrapper case_stack_height = CurrentStackHeight();
|
| Label next_test; // Recycled for each test.
|
| // Compile all the tests with branches to their bodies.
|
| for (int i = 0; i < clauses->length(); i++) {
|
| @@ -961,6 +966,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
|
|
|
| Comment cmnt(masm_, "[ Case comparison");
|
| __ bind(&next_test);
|
| + SetStackHeight(case_stack_height);
|
| next_test.Unuse();
|
|
|
| // Compile the label expression.
|
| @@ -978,9 +984,10 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
|
|
|
| __ cmp(edx, eax);
|
| __ j(not_equal, &next_test);
|
| - __ Drop(1); // Switch value is no longer needed.
|
| + AsmDrop(1); // Switch value is no longer needed.
|
| __ jmp(clause->body_target());
|
| __ bind(&slow_case);
|
| + SetStackHeight(case_stack_height);
|
| }
|
|
|
| // Record position before stub call for type feedback.
|
| @@ -992,22 +999,26 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
|
| Label skip;
|
| __ jmp(&skip, Label::kNear);
|
| PrepareForBailout(clause, TOS_REG);
|
| +
|
| + ASSERT(case_stack_height.get() == stack_height_.get());
|
| __ cmp(eax, isolate()->factory()->true_value());
|
| __ j(not_equal, &next_test);
|
| - __ Drop(1);
|
| + AsmDrop(1);
|
| __ jmp(clause->body_target());
|
| __ bind(&skip);
|
| + SetStackHeight(case_stack_height);
|
|
|
| __ test(eax, eax);
|
| __ j(not_equal, &next_test);
|
| - __ Drop(1); // Switch value is no longer needed.
|
| + AsmDrop(1); // Switch value is no longer needed.
|
| __ jmp(clause->body_target());
|
| }
|
|
|
| // Discard the test value and jump to the default if present, otherwise to
|
| // the end of the statement.
|
| __ bind(&next_test);
|
| - __ Drop(1); // Switch value is no longer needed.
|
| + SetStackHeight(case_stack_height);
|
| + AsmDrop(1); // Switch value is no longer needed.
|
| if (default_clause == NULL) {
|
| __ jmp(nested_statement.break_label());
|
| } else {
|
| @@ -1054,10 +1065,10 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
|
| __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
|
| __ j(above_equal, &done_convert, Label::kNear);
|
| __ bind(&convert);
|
| - __ push(eax);
|
| - __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
| + AsmPush(eax);
|
| + AsmInvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION, 1);
|
| __ bind(&done_convert);
|
| - __ push(eax);
|
| + AsmPush(eax);
|
|
|
| // Check for proxies.
|
| Label call_runtime, use_cache, fixed_array;
|
| @@ -1076,10 +1087,11 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
|
|
|
| // Get the set of properties to enumerate.
|
| __ bind(&call_runtime);
|
| - __ push(eax);
|
| - __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
|
| + AsmPush(eax);
|
| + AsmCallRuntime(Runtime::kGetPropertyNamesFast, 1);
|
| __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
|
| isolate()->factory()->meta_map());
|
| + StackHeightWrapper top_stack_height = CurrentStackHeight();
|
| __ j(not_equal, &fixed_array);
|
|
|
|
|
| @@ -1096,19 +1108,22 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
|
| __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
|
|
|
| // Set up the four remaining stack slots.
|
| - __ push(eax); // Map.
|
| - __ push(ecx); // Enumeration cache.
|
| - __ push(edx); // Number of valid entries for the map in the enum cache.
|
| - __ push(Immediate(Smi::FromInt(0))); // Initial index.
|
| + AsmPush(eax); // Map.
|
| + AsmPush(ecx); // Enumeration cache.
|
| + AsmPush(edx); // Number of valid entries for the map in the enum cache.
|
| + AsmPushSmi(Smi::FromInt(0)); // Initial index.
|
| __ jmp(&loop);
|
|
|
| __ bind(&no_descriptors);
|
| - __ add(esp, Immediate(kPointerSize));
|
| + SetStackHeight(top_stack_height);
|
| + AsmDrop(1);
|
| + StackHeightWrapper exit_stack_height = CurrentStackHeight();
|
| __ jmp(&exit);
|
|
|
| // We got a fixed array in register eax. Iterate through that.
|
| Label non_proxy;
|
| __ bind(&fixed_array);
|
| + SetStackHeight(top_stack_height);
|
|
|
| // No need for a write barrier, we are storing a Smi in the feedback vector.
|
| __ LoadHeapObject(ebx, FeedbackVector());
|
| @@ -1122,15 +1137,15 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
|
| __ j(above, &non_proxy);
|
| __ Move(ebx, Immediate(Smi::FromInt(0))); // Zero indicates proxy
|
| __ bind(&non_proxy);
|
| - __ push(ebx); // Smi
|
| - __ push(eax); // Array
|
| + AsmPush(ebx); // Smi
|
| + AsmPush(eax); // Array
|
| __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset));
|
| - __ push(eax); // Fixed array length (as smi).
|
| - __ push(Immediate(Smi::FromInt(0))); // Initial index.
|
| + AsmPush(eax); // Fixed array length (as smi).
|
| + AsmPushSmi(Smi::FromInt(0)); // Initial index.
|
|
|
| // Generate code for doing the condition check.
|
| - PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
|
| __ bind(&loop);
|
| + PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
|
| __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index.
|
| __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length.
|
| __ j(above_equal, loop_statement.break_label());
|
| @@ -1154,14 +1169,15 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
|
| // TODO(rossberg): What if only a prototype is a proxy? Not specified yet.
|
| ASSERT(Smi::FromInt(0) == 0);
|
| __ test(edx, edx);
|
| + StackHeightWrapper update_each_stack_height = CurrentStackHeight();
|
| __ j(zero, &update_each);
|
|
|
| // Convert the entry to a string or null if it isn't a property
|
| // anymore. If the property has been removed while iterating, we
|
| // just skip it.
|
| - __ push(ecx); // Enumerable.
|
| - __ push(ebx); // Current entry.
|
| - __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
|
| + AsmPush(ecx); // Enumerable.
|
| + AsmPush(ebx); // Current entry.
|
| + AsmInvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION, 2);
|
| __ test(eax, eax);
|
| __ j(equal, loop_statement.continue_label());
|
| __ mov(ebx, eax);
|
| @@ -1169,6 +1185,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
|
| // Update the 'each' property or variable from the possibly filtered
|
| // entry in register ebx.
|
| __ bind(&update_each);
|
| + USE(update_each_stack_height);
|
| + ASSERT(update_each_stack_height.get() == stack_height_.get());
|
| __ mov(result_register(), ebx);
|
| // Perform the assignment as if via '='.
|
| { EffectContext context(this);
|
| @@ -1188,12 +1206,13 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
|
|
|
| // Remove the pointers stored on the stack.
|
| __ bind(loop_statement.break_label());
|
| - __ add(esp, Immediate(5 * kPointerSize));
|
| + AsmDrop(5);
|
|
|
| // Exit and decrement the loop depth.
|
| - PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
|
| __ bind(&exit);
|
| + PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
|
| decrement_loop_depth();
|
| + SetStackHeight(exit_stack_height);
|
| }
|
|
|
|
|
| @@ -1219,8 +1238,8 @@ void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
|
| __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
|
| __ j(above_equal, &done_convert);
|
| __ bind(&convert);
|
| - __ push(eax);
|
| - __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
|
| + AsmPush(eax);
|
| + AsmInvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION, 1);
|
| __ bind(&done_convert);
|
|
|
| // Loop entry.
|
| @@ -1274,12 +1293,12 @@ void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
|
| __ mov(ebx, Immediate(info));
|
| __ CallStub(&stub);
|
| } else {
|
| - __ push(esi);
|
| - __ push(Immediate(info));
|
| - __ push(Immediate(pretenure
|
| - ? isolate()->factory()->true_value()
|
| - : isolate()->factory()->false_value()));
|
| - __ CallRuntime(Runtime::kHiddenNewClosure, 3);
|
| + AsmPush(esi);
|
| + AsmPushHandle(info);
|
| + AsmPushHandle(pretenure
|
| + ? isolate()->factory()->true_value()
|
| + : isolate()->factory()->false_value());
|
| + AsmCallRuntime(Runtime::kHiddenNewClosure, 3);
|
| }
|
| context()->Plug(eax);
|
| }
|
| @@ -1403,8 +1422,8 @@ void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
|
| if (local->mode() == CONST_LEGACY) {
|
| __ mov(eax, isolate()->factory()->undefined_value());
|
| } else { // LET || CONST
|
| - __ push(Immediate(var->name()));
|
| - __ CallRuntime(Runtime::kHiddenThrowReferenceError, 1);
|
| + AsmPushHandle(var->name());
|
| + AsmCallRuntime(Runtime::kHiddenThrowReferenceError, 1);
|
| }
|
| }
|
| __ jmp(done);
|
| @@ -1480,8 +1499,8 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
|
| if (var->mode() == LET || var->mode() == CONST) {
|
| // Throw a reference error when using an uninitialized let/const
|
| // binding in harmony mode.
|
| - __ push(Immediate(var->name()));
|
| - __ CallRuntime(Runtime::kHiddenThrowReferenceError, 1);
|
| + AsmPushHandle(var->name());
|
| + AsmCallRuntime(Runtime::kHiddenThrowReferenceError, 1);
|
| } else {
|
| // Uninitalized const bindings outside of harmony mode are unholed.
|
| ASSERT(var->mode() == CONST_LEGACY);
|
| @@ -1503,9 +1522,9 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
|
| // by eval-introduced variables.
|
| EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done);
|
| __ bind(&slow);
|
| - __ push(esi); // Context.
|
| - __ push(Immediate(var->name()));
|
| - __ CallRuntime(Runtime::kHiddenLoadContextSlot, 2);
|
| + AsmPush(esi); // Context.
|
| + AsmPushHandle(var->name());
|
| + AsmCallRuntime(Runtime::kHiddenLoadContextSlot, 2);
|
| __ bind(&done);
|
| context()->Plug(eax);
|
| break;
|
| @@ -1532,11 +1551,11 @@ void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
|
|
|
| // Create regexp literal using runtime function
|
| // Result will be in eax.
|
| - __ push(ecx);
|
| - __ push(Immediate(Smi::FromInt(expr->literal_index())));
|
| - __ push(Immediate(expr->pattern()));
|
| - __ push(Immediate(expr->flags()));
|
| - __ CallRuntime(Runtime::kHiddenMaterializeRegExpLiteral, 4);
|
| + AsmPush(ecx);
|
| + AsmPushSmi(Smi::FromInt(expr->literal_index()));
|
| + AsmPushHandle(expr->pattern());
|
| + AsmPushHandle(expr->flags());
|
| + AsmCallRuntime(Runtime::kHiddenMaterializeRegExpLiteral, 4);
|
| __ mov(ebx, eax);
|
|
|
| __ bind(&materialized);
|
| @@ -1546,10 +1565,10 @@ void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
|
| __ jmp(&allocated);
|
|
|
| __ bind(&runtime_allocate);
|
| - __ push(ebx);
|
| - __ push(Immediate(Smi::FromInt(size)));
|
| - __ CallRuntime(Runtime::kHiddenAllocateInNewSpace, 1);
|
| - __ pop(ebx);
|
| + AsmPush(ebx);
|
| + AsmPushSmi(Smi::FromInt(size));
|
| + AsmCallRuntime(Runtime::kHiddenAllocateInNewSpace, 1);
|
| + AsmPop(ebx);
|
|
|
| __ bind(&allocated);
|
| // Copy the content into the newly allocated memory.
|
| @@ -1570,7 +1589,7 @@ void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
|
|
|
| void FullCodeGenerator::EmitAccessor(Expression* expression) {
|
| if (expression == NULL) {
|
| - __ push(Immediate(isolate()->factory()->null_value()));
|
| + AsmPushHandle(isolate()->factory()->null_value());
|
| } else {
|
| VisitForStackValue(expression);
|
| }
|
| @@ -1594,11 +1613,11 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
| flags != ObjectLiteral::kFastElements ||
|
| properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
|
| __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
|
| - __ push(FieldOperand(edi, JSFunction::kLiteralsOffset));
|
| - __ push(Immediate(Smi::FromInt(expr->literal_index())));
|
| - __ push(Immediate(constant_properties));
|
| - __ push(Immediate(Smi::FromInt(flags)));
|
| - __ CallRuntime(Runtime::kHiddenCreateObjectLiteral, 4);
|
| + AsmPush(FieldOperand(edi, JSFunction::kLiteralsOffset));
|
| + AsmPushSmi(Smi::FromInt(expr->literal_index()));
|
| + AsmPushHandle(constant_properties);
|
| + AsmPushSmi(Smi::FromInt(flags));
|
| + AsmCallRuntime(Runtime::kHiddenCreateObjectLiteral, 4);
|
| } else {
|
| __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
|
| __ mov(eax, FieldOperand(edi, JSFunction::kLiteralsOffset));
|
| @@ -1626,7 +1645,7 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
| Literal* key = property->key();
|
| Expression* value = property->value();
|
| if (!result_saved) {
|
| - __ push(eax); // Save result on the stack
|
| + AsmPush(eax); // Save result on the stack
|
| result_saved = true;
|
| }
|
| switch (property->kind()) {
|
| @@ -1648,23 +1667,23 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
| }
|
| break;
|
| }
|
| - __ push(Operand(esp, 0)); // Duplicate receiver.
|
| + AsmPush(Operand(esp, 0)); // Duplicate receiver.
|
| VisitForStackValue(key);
|
| VisitForStackValue(value);
|
| if (property->emit_store()) {
|
| - __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes
|
| - __ CallRuntime(Runtime::kSetProperty, 4);
|
| + AsmPushSmi(Smi::FromInt(NONE)); // PropertyAttributes
|
| + AsmCallRuntime(Runtime::kSetProperty, 4);
|
| } else {
|
| - __ Drop(3);
|
| + AsmDrop(3);
|
| }
|
| break;
|
| case ObjectLiteral::Property::PROTOTYPE:
|
| - __ push(Operand(esp, 0)); // Duplicate receiver.
|
| + AsmPush(Operand(esp, 0)); // Duplicate receiver.
|
| VisitForStackValue(value);
|
| if (property->emit_store()) {
|
| - __ CallRuntime(Runtime::kSetPrototype, 2);
|
| + AsmCallRuntime(Runtime::kSetPrototype, 2);
|
| } else {
|
| - __ Drop(2);
|
| + AsmDrop(2);
|
| }
|
| break;
|
| case ObjectLiteral::Property::GETTER:
|
| @@ -1676,23 +1695,24 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
| }
|
| }
|
|
|
| +
|
| // Emit code to define accessors, using only a single call to the runtime for
|
| // each pair of corresponding getters and setters.
|
| for (AccessorTable::Iterator it = accessor_table.begin();
|
| it != accessor_table.end();
|
| ++it) {
|
| - __ push(Operand(esp, 0)); // Duplicate receiver.
|
| + AsmPush(Operand(esp, 0)); // Duplicate receiver.
|
| VisitForStackValue(it->first);
|
| EmitAccessor(it->second->getter);
|
| EmitAccessor(it->second->setter);
|
| - __ push(Immediate(Smi::FromInt(NONE)));
|
| - __ CallRuntime(Runtime::kDefineOrRedefineAccessorProperty, 5);
|
| + AsmPushSmi(Smi::FromInt(NONE));
|
| + AsmCallRuntime(Runtime::kDefineOrRedefineAccessorProperty, 5);
|
| }
|
|
|
| if (expr->has_function()) {
|
| ASSERT(result_saved);
|
| - __ push(Operand(esp, 0));
|
| - __ CallRuntime(Runtime::kToFastProperties, 1);
|
| + AsmPush(Operand(esp, 0));
|
| + AsmCallRuntime(Runtime::kToFastProperties, 1);
|
| }
|
|
|
| if (result_saved) {
|
| @@ -1731,11 +1751,11 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
|
|
|
| if (expr->depth() > 1) {
|
| __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
|
| - __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
|
| - __ push(Immediate(Smi::FromInt(expr->literal_index())));
|
| - __ push(Immediate(constant_elements));
|
| - __ push(Immediate(Smi::FromInt(flags)));
|
| - __ CallRuntime(Runtime::kHiddenCreateArrayLiteral, 4);
|
| + AsmPush(FieldOperand(ebx, JSFunction::kLiteralsOffset));
|
| + AsmPushSmi(Smi::FromInt(expr->literal_index()));
|
| + AsmPushHandle(constant_elements);
|
| + AsmPushSmi(Smi::FromInt(flags));
|
| + AsmCallRuntime(Runtime::kHiddenCreateArrayLiteral, 4);
|
| } else {
|
| __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
|
| __ mov(eax, FieldOperand(ebx, JSFunction::kLiteralsOffset));
|
| @@ -1756,8 +1776,8 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
|
| if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
|
|
|
| if (!result_saved) {
|
| - __ push(eax); // array literal.
|
| - __ push(Immediate(Smi::FromInt(expr->literal_index())));
|
| + AsmPush(eax); // array literal.
|
| + AsmPushSmi(Smi::FromInt(expr->literal_index()));
|
| result_saved = true;
|
| }
|
| VisitForAccumulatorValue(subexpr);
|
| @@ -1786,7 +1806,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
|
| }
|
|
|
| if (result_saved) {
|
| - __ add(esp, Immediate(kPointerSize)); // literal index
|
| + AsmDrop(1);
|
| context()->PlugTOS();
|
| } else {
|
| context()->Plug(eax);
|
| @@ -1860,7 +1880,7 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
| }
|
|
|
| Token::Value op = expr->binary_op();
|
| - __ push(eax); // Left operand goes on the stack.
|
| + AsmPush(eax); // Left operand goes on the stack.
|
| VisitForAccumulatorValue(expr->value());
|
|
|
| OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
|
| @@ -1914,7 +1934,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
|
| case Yield::SUSPEND:
|
| // Pop value from top-of-stack slot; box result into result register.
|
| EmitCreateIteratorResult(false);
|
| - __ push(result_register());
|
| + AsmPush(result_register());
|
| // Fall through.
|
| case Yield::INITIAL: {
|
| Label suspend, continuation, post_runtime, resume;
|
| @@ -1936,12 +1956,12 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
|
| __ lea(ebx, Operand(ebp, StandardFrameConstants::kExpressionsOffset));
|
| __ cmp(esp, ebx);
|
| __ j(equal, &post_runtime);
|
| - __ push(eax); // generator object
|
| - __ CallRuntime(Runtime::kHiddenSuspendJSGeneratorObject, 1);
|
| + AsmPush(eax); // generator object
|
| + AsmCallRuntime(Runtime::kHiddenSuspendJSGeneratorObject, 1);
|
| __ mov(context_register(),
|
| Operand(ebp, StandardFrameConstants::kContextOffset));
|
| __ bind(&post_runtime);
|
| - __ pop(result_register());
|
| + AsmPop(result_register());
|
| EmitReturnSequence();
|
|
|
| __ bind(&resume);
|
| @@ -1956,8 +1976,10 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
|
| Immediate(Smi::FromInt(JSGeneratorObject::kGeneratorClosed)));
|
| // Pop value from top-of-stack slot, box result into result register.
|
| EmitCreateIteratorResult(true);
|
| + StackHeightWrapper final_stack_height = CurrentStackHeight();
|
| EmitUnwindBeforeReturn();
|
| EmitReturnSequence();
|
| + SetStackHeight(final_stack_height);
|
| break;
|
| }
|
|
|
| @@ -1972,32 +1994,35 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
|
| Label l_next, l_call, l_loop;
|
| // Initial send value is undefined.
|
| __ mov(eax, isolate()->factory()->undefined_value());
|
| + StackHeightWrapper next_stack_height = CurrentStackHeight();
|
| __ jmp(&l_next);
|
|
|
| // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; }
|
| __ bind(&l_catch);
|
| handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos()));
|
| __ mov(ecx, isolate()->factory()->throw_string()); // "throw"
|
| - __ push(ecx); // "throw"
|
| - __ push(Operand(esp, 2 * kPointerSize)); // iter
|
| - __ push(eax); // exception
|
| + AsmPush(ecx); // "throw"
|
| + AsmPush(Operand(esp, 2 * kPointerSize)); // iter
|
| + AsmPush(eax); // exception
|
| __ jmp(&l_call);
|
|
|
| // try { received = %yield result }
|
| // Shuffle the received result above a try handler and yield it without
|
| // re-boxing.
|
| __ bind(&l_try);
|
| - __ pop(eax); // result
|
| - __ PushTryHandler(StackHandler::CATCH, expr->index());
|
| + SetStackHeight(next_stack_height);
|
| + UpdateStackHeight(1);
|
| + AsmPop(eax); // result
|
| + AsmPushTryHandler(StackHandler::CATCH, expr->index());
|
| const int handler_size = StackHandlerConstants::kSize;
|
| - __ push(eax); // result
|
| + AsmPush(eax); // result
|
| __ jmp(&l_suspend);
|
| __ bind(&l_continuation);
|
| __ jmp(&l_resume);
|
| __ bind(&l_suspend);
|
| const int generator_object_depth = kPointerSize + handler_size;
|
| __ mov(eax, Operand(esp, generator_object_depth));
|
| - __ push(eax); // g
|
| + AsmPush(eax); // g
|
| ASSERT(l_continuation.pos() > 0 && Smi::IsValid(l_continuation.pos()));
|
| __ mov(FieldOperand(eax, JSGeneratorObject::kContinuationOffset),
|
| Immediate(Smi::FromInt(l_continuation.pos())));
|
| @@ -2005,20 +2030,21 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
|
| __ mov(ecx, esi);
|
| __ RecordWriteField(eax, JSGeneratorObject::kContextOffset, ecx, edx,
|
| kDontSaveFPRegs);
|
| - __ CallRuntime(Runtime::kHiddenSuspendJSGeneratorObject, 1);
|
| + AsmCallRuntime(Runtime::kHiddenSuspendJSGeneratorObject, 1);
|
| __ mov(context_register(),
|
| Operand(ebp, StandardFrameConstants::kContextOffset));
|
| - __ pop(eax); // result
|
| + AsmPop(eax); // result
|
| EmitReturnSequence();
|
| __ bind(&l_resume); // received in eax
|
| - __ PopTryHandler();
|
| + AsmPopTryHandler();
|
|
|
| // receiver = iter; f = iter.next; arg = received;
|
| __ bind(&l_next);
|
| + SetStackHeight(next_stack_height);
|
| __ mov(ecx, isolate()->factory()->next_string()); // "next"
|
| - __ push(ecx);
|
| - __ push(Operand(esp, 2 * kPointerSize)); // iter
|
| - __ push(eax); // received
|
| + AsmPush(ecx);
|
| + AsmPush(Operand(esp, 2 * kPointerSize)); // iter
|
| + AsmPush(eax); // received
|
|
|
| // result = receiver[f](arg);
|
| __ bind(&l_call);
|
| @@ -2028,14 +2054,14 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
|
| __ mov(edi, eax);
|
| __ mov(Operand(esp, 2 * kPointerSize), edi);
|
| CallFunctionStub stub(isolate(), 1, CALL_AS_METHOD);
|
| - __ CallStub(&stub);
|
| + AsmCallStub(&stub, 2);
|
|
|
| __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| - __ Drop(1); // The function is still on the stack; drop it.
|
| + AsmDrop(1); // The key is still on the stack; drop it.
|
|
|
| // if (!result.done) goto l_try;
|
| __ bind(&l_loop);
|
| - __ push(eax); // save result
|
| + AsmPush(eax); // save result
|
| __ mov(edx, eax); // result
|
| __ mov(ecx, isolate()->factory()->done_string()); // "done"
|
| CallLoadIC(NOT_CONTEXTUAL); // result.done in eax
|
| @@ -2045,7 +2071,7 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
|
| __ j(zero, &l_try);
|
|
|
| // result.value
|
| - __ pop(edx); // result
|
| + AsmPop(edx); // result
|
| __ mov(ecx, isolate()->factory()->value_string()); // "value"
|
| CallLoadIC(NOT_CONTEXTUAL); // result.value in eax
|
| context()->DropAndPlug(2, eax); // drop iter and g
|
| @@ -2064,7 +2090,7 @@ void FullCodeGenerator::EmitGeneratorResume(Expression *generator,
|
| // ebx will hold the generator object until the activation has been resumed.
|
| VisitForStackValue(generator);
|
| VisitForAccumulatorValue(value);
|
| - __ pop(ebx);
|
| + AsmPop(ebx);
|
|
|
| // Check generator state.
|
| Label wrong_state, closed_state, done;
|
| @@ -2147,20 +2173,20 @@ void FullCodeGenerator::EmitGeneratorResume(Expression *generator,
|
| __ bind(&closed_state);
|
| if (resume_mode == JSGeneratorObject::NEXT) {
|
| // Return completed iterator result when generator is closed.
|
| - __ push(Immediate(isolate()->factory()->undefined_value()));
|
| + AsmPushHandle(isolate()->factory()->undefined_value());
|
| // Pop value from top-of-stack slot; box result into result register.
|
| EmitCreateIteratorResult(true);
|
| } else {
|
| // Throw the provided value.
|
| - __ push(eax);
|
| - __ CallRuntime(Runtime::kHiddenThrow, 1);
|
| + AsmPush(eax);
|
| + AsmCallRuntime(Runtime::kHiddenThrow, 1);
|
| }
|
| __ jmp(&done);
|
|
|
| // Throw error if we attempt to operate on a running generator.
|
| __ bind(&wrong_state);
|
| - __ push(ebx);
|
| - __ CallRuntime(Runtime::kHiddenThrowGeneratorStateError, 1);
|
| + AsmPush(ebx);
|
| + AsmCallRuntime(Runtime::kHiddenThrowGeneratorStateError, 1);
|
|
|
| __ bind(&done);
|
| context()->Plug(result_register());
|
| @@ -2177,14 +2203,14 @@ void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
|
| __ jmp(&allocated);
|
|
|
| __ bind(&gc_required);
|
| - __ Push(Smi::FromInt(map->instance_size()));
|
| - __ CallRuntime(Runtime::kHiddenAllocateInNewSpace, 1);
|
| + AsmPushSmi(Smi::FromInt(map->instance_size()));
|
| + AsmCallRuntime(Runtime::kHiddenAllocateInNewSpace, 1);
|
| __ mov(context_register(),
|
| Operand(ebp, StandardFrameConstants::kContextOffset));
|
|
|
| __ bind(&allocated);
|
| __ mov(ebx, map);
|
| - __ pop(ecx);
|
| + AsmPop(ecx);
|
| __ mov(edx, isolate()->factory()->ToBoolean(done));
|
| ASSERT_EQ(map->instance_size(), 5 * kPointerSize);
|
| __ mov(FieldOperand(eax, HeapObject::kMapOffset), ebx);
|
| @@ -2226,7 +2252,7 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
|
| // Do combined smi check of the operands. Left operand is on the
|
| // stack. Right operand is in eax.
|
| Label smi_case, done, stub_call;
|
| - __ pop(edx);
|
| + AsmPop(edx);
|
| __ mov(ecx, eax);
|
| __ or_(eax, edx);
|
| JumpPatchSite patch_site(masm_);
|
| @@ -2316,7 +2342,7 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
|
| void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
|
| Token::Value op,
|
| OverwriteMode mode) {
|
| - __ pop(edx);
|
| + AsmPop(edx);
|
| BinaryOpICStub stub(isolate(), op, mode);
|
| JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
|
| CallIC(stub.GetCode(), expr->BinaryOperationFeedbackId());
|
| @@ -2347,21 +2373,21 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) {
|
| break;
|
| }
|
| case NAMED_PROPERTY: {
|
| - __ push(eax); // Preserve value.
|
| + AsmPush(eax); // Preserve value.
|
| VisitForAccumulatorValue(prop->obj());
|
| __ mov(edx, eax);
|
| - __ pop(eax); // Restore value.
|
| + AsmPop(eax); // Restore value.
|
| __ mov(ecx, prop->key()->AsLiteral()->value());
|
| CallStoreIC();
|
| break;
|
| }
|
| case KEYED_PROPERTY: {
|
| - __ push(eax); // Preserve value.
|
| + AsmPush(eax); // Preserve value.
|
| VisitForStackValue(prop->obj());
|
| VisitForAccumulatorValue(prop->key());
|
| __ mov(ecx, eax);
|
| - __ pop(edx); // Receiver.
|
| - __ pop(eax); // Restore value.
|
| + AsmPop(edx); // Receiver.
|
| + AsmPop(eax); // Restore value.
|
| Handle<Code> ic = strict_mode() == SLOPPY
|
| ? isolate()->builtins()->KeyedStoreIC_Initialize()
|
| : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
|
| @@ -2406,10 +2432,10 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
|
| // Const initializers need a write barrier.
|
| ASSERT(!var->IsParameter()); // No const parameters.
|
| if (var->IsLookupSlot()) {
|
| - __ push(eax);
|
| - __ push(esi);
|
| - __ push(Immediate(var->name()));
|
| - __ CallRuntime(Runtime::kHiddenInitializeConstContextSlot, 3);
|
| + AsmPush(eax);
|
| + AsmPush(esi);
|
| + AsmPushHandle(var->name());
|
| + AsmCallRuntime(Runtime::kHiddenInitializeConstContextSlot, 3);
|
| } else {
|
| ASSERT(var->IsStackLocal() || var->IsContextSlot());
|
| Label skip;
|
| @@ -2432,8 +2458,8 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
|
| __ mov(edx, location);
|
| __ cmp(edx, isolate()->factory()->the_hole_value());
|
| __ j(not_equal, &assign, Label::kNear);
|
| - __ push(Immediate(var->name()));
|
| - __ CallRuntime(Runtime::kHiddenThrowReferenceError, 1);
|
| + AsmPushHandle(var->name());
|
| + AsmCallRuntime(Runtime::kHiddenThrowReferenceError, 1);
|
| __ bind(&assign);
|
| EmitStoreToStackLocalOrContextSlot(var, location);
|
| }
|
| @@ -2471,7 +2497,7 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
|
| // Record source code position before IC call.
|
| SetSourcePosition(expr->position());
|
| __ mov(ecx, prop->key()->AsLiteral()->value());
|
| - __ pop(edx);
|
| + AsmPop(edx);
|
| CallStoreIC(expr->AssignmentFeedbackId());
|
| PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
|
| context()->Plug(eax);
|
| @@ -2484,8 +2510,8 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
|
| // esp[0] : key
|
| // esp[kPointerSize] : receiver
|
|
|
| - __ pop(ecx); // Key.
|
| - __ pop(edx);
|
| + AsmPop(ecx); // Key.
|
| + AsmPop(edx);
|
| // Record source code position before IC call.
|
| SetSourcePosition(expr->position());
|
| Handle<Code> ic = strict_mode() == SLOPPY
|
| @@ -2511,7 +2537,7 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
|
| } else {
|
| VisitForStackValue(expr->obj());
|
| VisitForAccumulatorValue(expr->key());
|
| - __ pop(edx); // Object.
|
| + AsmPop(edx); // Object.
|
| __ mov(ecx, result_register()); // Key.
|
| EmitKeyedPropertyLoad(expr);
|
| context()->Plug(eax);
|
| @@ -2541,7 +2567,7 @@ void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
|
| }
|
| // Push undefined as receiver. This is patched in the method prologue if it
|
| // is a sloppy mode method.
|
| - __ push(Immediate(isolate()->factory()->undefined_value()));
|
| + AsmPushHandle(isolate()->factory()->undefined_value());
|
| } else {
|
| // Load the function from the receiver.
|
| ASSERT(callee->IsProperty());
|
| @@ -2549,7 +2575,7 @@ void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
|
| EmitNamedPropertyLoad(callee->AsProperty());
|
| PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
|
| // Push the target function under the receiver.
|
| - __ push(Operand(esp, 0));
|
| + AsmPush(Operand(esp, 0));
|
| __ mov(Operand(esp, kPointerSize), eax);
|
| }
|
|
|
| @@ -2574,7 +2600,7 @@ void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr,
|
| PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
|
|
|
| // Push the target function under the receiver.
|
| - __ push(Operand(esp, 0));
|
| + AsmPush(Operand(esp, 0));
|
| __ mov(Operand(esp, kPointerSize), eax);
|
|
|
| EmitCall(expr, CallIC::METHOD);
|
| @@ -2600,9 +2626,9 @@ void FullCodeGenerator::EmitCall(Call* expr, CallIC::CallType call_type) {
|
| // Don't assign a type feedback id to the IC, since type feedback is provided
|
| // by the vector above.
|
| CallIC(ic);
|
| + UpdateStackHeight(-(arg_count + 1));
|
|
|
| RecordJSReturnSite(expr);
|
| -
|
| // Restore context register.
|
| __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
|
|
| @@ -2613,21 +2639,21 @@ void FullCodeGenerator::EmitCall(Call* expr, CallIC::CallType call_type) {
|
| void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
|
| // Push copy of the first argument or undefined if it doesn't exist.
|
| if (arg_count > 0) {
|
| - __ push(Operand(esp, arg_count * kPointerSize));
|
| + AsmPush(Operand(esp, arg_count * kPointerSize));
|
| } else {
|
| - __ push(Immediate(isolate()->factory()->undefined_value()));
|
| + AsmPushHandle(isolate()->factory()->undefined_value());
|
| }
|
|
|
| // Push the receiver of the enclosing function.
|
| - __ push(Operand(ebp, (2 + info_->scope()->num_parameters()) * kPointerSize));
|
| + AsmPush(Operand(ebp, (2 + info_->scope()->num_parameters()) * kPointerSize));
|
| // Push the language mode.
|
| - __ push(Immediate(Smi::FromInt(strict_mode())));
|
| + AsmPushSmi(Smi::FromInt(strict_mode()));
|
|
|
| // Push the start position of the scope the calls resides in.
|
| - __ push(Immediate(Smi::FromInt(scope()->start_position())));
|
| + AsmPushSmi(Smi::FromInt(scope()->start_position()));
|
|
|
| // Do the runtime call.
|
| - __ CallRuntime(Runtime::kHiddenResolvePossiblyDirectEval, 5);
|
| + AsmCallRuntime(Runtime::kHiddenResolvePossiblyDirectEval, 5);
|
| }
|
|
|
|
|
| @@ -2651,7 +2677,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
| { PreservePositionScope pos_scope(masm()->positions_recorder());
|
| VisitForStackValue(callee);
|
| // Reserved receiver slot.
|
| - __ push(Immediate(isolate()->factory()->undefined_value()));
|
| + AsmPushHandle(isolate()->factory()->undefined_value());
|
| // Push the arguments.
|
| for (int i = 0; i < arg_count; i++) {
|
| VisitForStackValue(args->at(i));
|
| @@ -2659,7 +2685,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
|
|
| // Push a copy of the function (found below the arguments) and
|
| // resolve eval.
|
| - __ push(Operand(esp, (arg_count + 1) * kPointerSize));
|
| + AsmPush(Operand(esp, (arg_count + 1) * kPointerSize));
|
| EmitResolvePossiblyDirectEval(arg_count);
|
|
|
| // The runtime call returns a pair of values in eax (function) and
|
| @@ -2672,6 +2698,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
| CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS);
|
| __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
|
| __ CallStub(&stub);
|
| + UpdateStackHeight(-(arg_count + 1));
|
| RecordJSReturnSite(expr);
|
| // Restore context register.
|
| __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| @@ -2690,13 +2717,14 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
| EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done);
|
| }
|
| __ bind(&slow);
|
| + StackHeightWrapper branch_stack_height = CurrentStackHeight();
|
| // Call the runtime to find the function to call (returned in eax) and
|
| // the object holding it (returned in edx).
|
| - __ push(context_register());
|
| - __ push(Immediate(proxy->name()));
|
| - __ CallRuntime(Runtime::kHiddenLoadContextSlot, 2);
|
| - __ push(eax); // Function.
|
| - __ push(edx); // Receiver.
|
| + AsmPush(context_register());
|
| + AsmPushHandle(proxy->name());
|
| + AsmCallRuntime(Runtime::kHiddenLoadContextSlot, 2);
|
| + AsmPush(eax); // Function.
|
| + AsmPush(edx); // 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.
|
| @@ -2704,11 +2732,12 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
| Label call;
|
| __ jmp(&call, Label::kNear);
|
| __ bind(&done);
|
| + SetStackHeight(branch_stack_height);
|
| // Push function.
|
| - __ push(eax);
|
| + AsmPush(eax);
|
| // The receiver is implicitly the global receiver. Indicate this by
|
| // passing the hole to the call function stub.
|
| - __ push(Immediate(isolate()->factory()->undefined_value()));
|
| + AsmPushHandle(isolate()->factory()->undefined_value());
|
| __ bind(&call);
|
| }
|
|
|
| @@ -2733,7 +2762,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
| { PreservePositionScope scope(masm()->positions_recorder());
|
| VisitForStackValue(callee);
|
| }
|
| - __ push(Immediate(isolate()->factory()->undefined_value()));
|
| + AsmPushHandle(isolate()->factory()->undefined_value());
|
| // Emit function call.
|
| EmitCall(expr);
|
| }
|
| @@ -2783,6 +2812,7 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
|
|
|
| CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
|
| __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
|
| + UpdateStackHeight(-(arg_count + 1));
|
| PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
|
| context()->Plug(eax);
|
| }
|
| @@ -3140,7 +3170,7 @@ void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
|
| context()->PrepareTest(&materialize_true, &materialize_false,
|
| &if_true, &if_false, &fall_through);
|
|
|
| - __ pop(ebx);
|
| + AsmPop(ebx);
|
| __ cmp(eax, ebx);
|
| PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
|
| Split(equal, if_true, if_false, fall_through);
|
| @@ -3256,7 +3286,7 @@ void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
|
| VisitForStackValue(args->at(0));
|
| VisitForStackValue(args->at(1));
|
| VisitForStackValue(args->at(2));
|
| - __ CallStub(&stub);
|
| + AsmCallStub(&stub, 3);
|
| context()->Plug(eax);
|
| }
|
|
|
| @@ -3270,7 +3300,7 @@ void FullCodeGenerator::EmitRegExpExec(CallRuntime* expr) {
|
| VisitForStackValue(args->at(1));
|
| VisitForStackValue(args->at(2));
|
| VisitForStackValue(args->at(3));
|
| - __ CallStub(&stub);
|
| + AsmCallStub(&stub, 4);
|
| context()->Plug(eax);
|
| }
|
|
|
| @@ -3333,7 +3363,7 @@ void FullCodeGenerator::EmitDateField(CallRuntime* expr) {
|
| }
|
|
|
| __ bind(¬_date_object);
|
| - __ CallRuntime(Runtime::kHiddenThrowNotDateError, 0);
|
| + AsmCallRuntime(Runtime::kHiddenThrowNotDateError, 0);
|
| __ bind(&done);
|
| context()->Plug(result);
|
| }
|
| @@ -3351,8 +3381,8 @@ void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) {
|
| VisitForStackValue(args->at(2)); // value
|
| VisitForAccumulatorValue(args->at(0)); // string
|
|
|
| - __ pop(value);
|
| - __ pop(index);
|
| + AsmPop(value);
|
| + AsmPop(index);
|
|
|
| if (FLAG_debug_code) {
|
| __ test(value, Immediate(kSmiTagMask));
|
| @@ -3386,8 +3416,8 @@ void FullCodeGenerator::EmitTwoByteSeqStringSetChar(CallRuntime* expr) {
|
| VisitForStackValue(args->at(1)); // index
|
| VisitForStackValue(args->at(2)); // value
|
| VisitForAccumulatorValue(args->at(0)); // string
|
| - __ pop(value);
|
| - __ pop(index);
|
| + AsmPop(value);
|
| + AsmPop(index);
|
|
|
| if (FLAG_debug_code) {
|
| __ test(value, Immediate(kSmiTagMask));
|
| @@ -3416,7 +3446,7 @@ void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
|
| VisitForStackValue(args->at(1));
|
|
|
| MathPowStub stub(isolate(), MathPowStub::ON_STACK);
|
| - __ CallStub(&stub);
|
| + AsmCallStub(&stub, 2);
|
| context()->Plug(eax);
|
| }
|
|
|
| @@ -3427,7 +3457,7 @@ void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
|
|
|
| VisitForStackValue(args->at(0)); // Load the object.
|
| VisitForAccumulatorValue(args->at(1)); // Load the value.
|
| - __ pop(ebx); // eax = value. ebx = object.
|
| + AsmPop(ebx); // eax = value. ebx = object.
|
|
|
| Label done;
|
| // If the object is a smi, return the value.
|
| @@ -3493,7 +3523,7 @@ void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
|
| Register index = eax;
|
| Register result = edx;
|
|
|
| - __ pop(object);
|
| + AsmPop(object);
|
|
|
| Label need_conversion;
|
| Label index_out_of_range;
|
| @@ -3540,7 +3570,7 @@ void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
|
| Register scratch = edx;
|
| Register result = eax;
|
|
|
| - __ pop(object);
|
| + AsmPop(object);
|
|
|
| Label need_conversion;
|
| Label index_out_of_range;
|
| @@ -3582,7 +3612,7 @@ void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
|
| VisitForStackValue(args->at(0));
|
| VisitForAccumulatorValue(args->at(1));
|
|
|
| - __ pop(edx);
|
| + AsmPop(edx);
|
| StringAddStub stub(isolate(), STRING_ADD_CHECK_BOTH, NOT_TENURED);
|
| __ CallStub(&stub);
|
| context()->Plug(eax);
|
| @@ -3597,7 +3627,7 @@ void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) {
|
| VisitForStackValue(args->at(1));
|
|
|
| StringCompareStub stub(isolate());
|
| - __ CallStub(&stub);
|
| + AsmCallStub(&stub, 2);
|
| context()->Plug(eax);
|
| }
|
|
|
| @@ -3616,18 +3646,21 @@ void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
|
| // Check for non-function argument (including proxy).
|
| __ JumpIfSmi(eax, &runtime);
|
| __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
|
| + StackHeightWrapper branch_stack_height = CurrentStackHeight();
|
| __ j(not_equal, &runtime);
|
|
|
| // InvokeFunction requires the function in edi. Move it in there.
|
| __ mov(edi, result_register());
|
| ParameterCount count(arg_count);
|
| __ InvokeFunction(edi, count, CALL_FUNCTION, NullCallWrapper());
|
| + UpdateStackHeight(-(arg_count + 1));
|
| __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| __ jmp(&done);
|
|
|
| __ bind(&runtime);
|
| - __ push(eax);
|
| - __ CallRuntime(Runtime::kCall, args->length());
|
| + SetStackHeight(branch_stack_height);
|
| + AsmPush(eax);
|
| + AsmCallRuntime(Runtime::kCall, args->length());
|
| __ bind(&done);
|
|
|
| context()->Plug(eax);
|
| @@ -3642,8 +3675,8 @@ void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
|
| VisitForStackValue(args->at(0));
|
| VisitForStackValue(args->at(1));
|
| VisitForAccumulatorValue(args->at(2));
|
| - __ pop(ebx);
|
| - __ pop(ecx);
|
| + AsmPop(ebx);
|
| + AsmPop(ecx);
|
| __ CallStub(&stub);
|
| context()->Plug(eax);
|
| }
|
| @@ -3689,9 +3722,9 @@ void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
|
|
|
| __ bind(¬_found);
|
| // Call runtime to perform the lookup.
|
| - __ push(cache);
|
| - __ push(key);
|
| - __ CallRuntime(Runtime::kHiddenGetFromCache, 2);
|
| + AsmPush(cache);
|
| + AsmPush(key);
|
| + AsmCallRuntime(Runtime::kHiddenGetFromCache, 2);
|
|
|
| __ bind(&done);
|
| context()->Plug(eax);
|
| @@ -3767,6 +3800,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) {
|
| Operand result_operand = Operand(esp, 1 * kPointerSize);
|
| Operand array_length_operand = Operand(esp, 0);
|
| __ sub(esp, Immediate(2 * kPointerSize));
|
| + UpdateStackHeight(2);
|
| __ cld();
|
| // Check that the array is a JSArray
|
| __ JumpIfSmi(array, &bailout);
|
| @@ -3993,7 +4027,7 @@ void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) {
|
| __ bind(&done);
|
| __ mov(eax, result_operand);
|
| // Drop temp values from the stack, and restore context register.
|
| - __ add(esp, Immediate(3 * kPointerSize));
|
| + AsmDrop(3);
|
|
|
| __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| context()->Plug(eax);
|
| @@ -4014,7 +4048,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
|
| if (expr->is_jsruntime()) {
|
| // Push the builtins object as receiver.
|
| __ mov(eax, GlobalObjectOperand());
|
| - __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset));
|
| + AsmPush(FieldOperand(eax, GlobalObject::kBuiltinsOffset));
|
|
|
| // Load the function from the receiver.
|
| __ mov(edx, Operand(esp, 0));
|
| @@ -4022,7 +4056,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
|
| CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId());
|
|
|
| // Push the target function under the receiver.
|
| - __ push(Operand(esp, 0));
|
| + AsmPush(Operand(esp, 0));
|
| __ mov(Operand(esp, kPointerSize), eax);
|
|
|
| // Code common for calls using the IC.
|
| @@ -4036,7 +4070,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
|
| SetSourcePosition(expr->position());
|
| CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS);
|
| __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
|
| - __ CallStub(&stub);
|
| + AsmCallStub(&stub, arg_count + 1);
|
| // Restore context register.
|
| __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| context()->DropAndPlug(1, eax);
|
| @@ -4049,7 +4083,7 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
|
| }
|
|
|
| // Call the C runtime function.
|
| - __ CallRuntime(expr->function(), arg_count);
|
| + AsmCallRuntime(expr->function(), arg_count);
|
|
|
| context()->Plug(eax);
|
| }
|
| @@ -4066,8 +4100,8 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
|
| if (property != NULL) {
|
| VisitForStackValue(property->obj());
|
| VisitForStackValue(property->key());
|
| - __ push(Immediate(Smi::FromInt(strict_mode())));
|
| - __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
|
| + AsmPushSmi(Smi::FromInt(strict_mode()));
|
| + AsmInvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 3);
|
| context()->Plug(eax);
|
| } else if (proxy != NULL) {
|
| Variable* var = proxy->var();
|
| @@ -4075,10 +4109,10 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
|
| // but "delete this" is allowed.
|
| ASSERT(strict_mode() == SLOPPY || var->is_this());
|
| if (var->IsUnallocated()) {
|
| - __ push(GlobalObjectOperand());
|
| - __ push(Immediate(var->name()));
|
| - __ push(Immediate(Smi::FromInt(SLOPPY)));
|
| - __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
|
| + AsmPush(GlobalObjectOperand());
|
| + AsmPushHandle(var->name());
|
| + AsmPushSmi(Smi::FromInt(SLOPPY));
|
| + AsmInvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 3);
|
| context()->Plug(eax);
|
| } else if (var->IsStackAllocated() || var->IsContextSlot()) {
|
| // Result of deleting non-global variables is false. 'this' is
|
| @@ -4088,9 +4122,9 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
|
| } else {
|
| // Non-global variable. Call the runtime to try to delete from the
|
| // context where the variable was introduced.
|
| - __ push(context_register());
|
| - __ push(Immediate(var->name()));
|
| - __ CallRuntime(Runtime::kHiddenDeleteContextSlot, 2);
|
| + AsmPush(context_register());
|
| + AsmPushHandle(var->name());
|
| + AsmCallRuntime(Runtime::kHiddenDeleteContextSlot, 2);
|
| context()->Plug(eax);
|
| }
|
| } else {
|
| @@ -4134,20 +4168,22 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
|
| &materialize_false,
|
| &materialize_true,
|
| &materialize_true);
|
| + StackHeightWrapper branch_stack_height = CurrentStackHeight();
|
| __ bind(&materialize_true);
|
| PrepareForBailoutForId(expr->MaterializeTrueId(), NO_REGISTERS);
|
| if (context()->IsAccumulatorValue()) {
|
| __ mov(eax, isolate()->factory()->true_value());
|
| } else {
|
| - __ Push(isolate()->factory()->true_value());
|
| + AsmPushHandle(isolate()->factory()->true_value());
|
| }
|
| __ jmp(&done, Label::kNear);
|
| __ bind(&materialize_false);
|
| + SetStackHeight(branch_stack_height);
|
| PrepareForBailoutForId(expr->MaterializeFalseId(), NO_REGISTERS);
|
| if (context()->IsAccumulatorValue()) {
|
| __ mov(eax, isolate()->factory()->false_value());
|
| } else {
|
| - __ Push(isolate()->factory()->false_value());
|
| + AsmPushHandle(isolate()->factory()->false_value());
|
| }
|
| __ bind(&done);
|
| }
|
| @@ -4159,7 +4195,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
|
| { StackValueContext context(this);
|
| VisitForTypeofValue(expr->expression());
|
| }
|
| - __ CallRuntime(Runtime::kTypeof, 1);
|
| + AsmCallRuntime(Runtime::kTypeof, 1);
|
| context()->Plug(eax);
|
| break;
|
| }
|
| @@ -4196,12 +4232,12 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
| } else {
|
| // Reserve space for result of postfix operation.
|
| if (expr->is_postfix() && !context()->IsEffect()) {
|
| - __ push(Immediate(Smi::FromInt(0)));
|
| + AsmPushSmi(Smi::FromInt(0));
|
| }
|
| if (assign_type == NAMED_PROPERTY) {
|
| // Put the object both on the stack and in edx.
|
| VisitForAccumulatorValue(prop->obj());
|
| - __ push(eax);
|
| + AsmPush(eax);
|
| __ mov(edx, eax);
|
| EmitNamedPropertyLoad(prop);
|
| } else {
|
| @@ -4228,6 +4264,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
| Label slow;
|
| patch_site.EmitJumpIfNotSmi(eax, &slow, Label::kNear);
|
|
|
| + StackHeightWrapper smi_stack_height = CurrentStackHeight();
|
| +
|
| // Save result for postfix expressions.
|
| if (expr->is_postfix()) {
|
| if (!context()->IsEffect()) {
|
| @@ -4236,7 +4274,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
| // of the stack.
|
| switch (assign_type) {
|
| case VARIABLE:
|
| - __ push(eax);
|
| + AsmPush(eax);
|
| break;
|
| case NAMED_PROPERTY:
|
| __ mov(Operand(esp, kPointerSize), eax);
|
| @@ -4262,6 +4300,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
| }
|
| __ jmp(&stub_call, Label::kNear);
|
| __ bind(&slow);
|
| + SetStackHeight(smi_stack_height);
|
| }
|
| ToNumberStub convert_stub(isolate());
|
| __ CallStub(&convert_stub);
|
| @@ -4274,7 +4313,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
| // of the stack.
|
| switch (assign_type) {
|
| case VARIABLE:
|
| - __ push(eax);
|
| + AsmPush(eax);
|
| break;
|
| case NAMED_PROPERTY:
|
| __ mov(Operand(esp, kPointerSize), eax);
|
| @@ -4324,7 +4363,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
| break;
|
| case NAMED_PROPERTY: {
|
| __ mov(ecx, prop->key()->AsLiteral()->value());
|
| - __ pop(edx);
|
| + AsmPop(edx);
|
| CallStoreIC(expr->CountStoreFeedbackId());
|
| PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
|
| if (expr->is_postfix()) {
|
| @@ -4337,8 +4376,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
| break;
|
| }
|
| case KEYED_PROPERTY: {
|
| - __ pop(ecx);
|
| - __ pop(edx);
|
| + AsmPop(ecx);
|
| + AsmPop(edx);
|
| Handle<Code> ic = strict_mode() == SLOPPY
|
| ? isolate()->builtins()->KeyedStoreIC_Initialize()
|
| : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
|
| @@ -4381,9 +4420,9 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
|
| EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done);
|
|
|
| __ bind(&slow);
|
| - __ push(esi);
|
| - __ push(Immediate(proxy->name()));
|
| - __ CallRuntime(Runtime::kHiddenLoadContextSlotNoReferenceError, 2);
|
| + AsmPush(esi);
|
| + AsmPushHandle(proxy->name());
|
| + AsmCallRuntime(Runtime::kHiddenLoadContextSlotNoReferenceError, 2);
|
| PrepareForBailout(expr, TOS_REG);
|
| __ bind(&done);
|
|
|
| @@ -4496,7 +4535,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
|
| switch (op) {
|
| case Token::IN:
|
| VisitForStackValue(expr->right());
|
| - __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
|
| + AsmInvokeBuiltin(Builtins::IN, CALL_FUNCTION, 2);
|
| PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
|
| __ cmp(eax, isolate()->factory()->true_value());
|
| Split(equal, if_true, if_false, fall_through);
|
| @@ -4505,7 +4544,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
|
| case Token::INSTANCEOF: {
|
| VisitForStackValue(expr->right());
|
| InstanceofStub stub(isolate(), InstanceofStub::kNoFlags);
|
| - __ CallStub(&stub);
|
| + AsmCallStub(&stub, 2);
|
| PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
|
| __ test(eax, eax);
|
| // The stub returns 0 for true.
|
| @@ -4516,7 +4555,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
|
| default: {
|
| VisitForAccumulatorValue(expr->right());
|
| Condition cc = CompareIC::ComputeCondition(op);
|
| - __ pop(edx);
|
| + AsmPop(edx);
|
|
|
| bool inline_smi_code = ShouldInlineSmiCase(op);
|
| JumpPatchSite patch_site(masm_);
|
| @@ -4612,15 +4651,15 @@ void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
|
| // as their closure, not the anonymous closure containing the global
|
| // code. Pass a smi sentinel and let the runtime look up the empty
|
| // function.
|
| - __ push(Immediate(Smi::FromInt(0)));
|
| + AsmPushSmi(Smi::FromInt(0));
|
| } else if (declaration_scope->is_eval_scope()) {
|
| // Contexts nested inside eval code have the same closure as the context
|
| // calling eval, not the anonymous closure containing the eval code.
|
| // Fetch it from the context.
|
| - __ push(ContextOperand(esi, Context::CLOSURE_INDEX));
|
| + AsmPush(ContextOperand(esi, Context::CLOSURE_INDEX));
|
| } else {
|
| ASSERT(declaration_scope->is_function_scope());
|
| - __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
|
| + AsmPush(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
|
| }
|
| }
|
|
|
| @@ -4631,65 +4670,90 @@ void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
|
| void FullCodeGenerator::EnterFinallyBlock() {
|
| // Cook return address on top of stack (smi encoded Code* delta)
|
| ASSERT(!result_register().is(edx));
|
| - __ pop(edx);
|
| + AsmPop(edx);
|
| __ sub(edx, Immediate(masm_->CodeObject()));
|
| STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
|
| STATIC_ASSERT(kSmiTag == 0);
|
| __ SmiTag(edx);
|
| - __ push(edx);
|
| + AsmPush(edx);
|
|
|
| // Store result register while executing finally block.
|
| - __ push(result_register());
|
| + AsmPush(result_register());
|
|
|
| // Store pending message while executing finally block.
|
| ExternalReference pending_message_obj =
|
| ExternalReference::address_of_pending_message_obj(isolate());
|
| __ mov(edx, Operand::StaticVariable(pending_message_obj));
|
| - __ push(edx);
|
| + AsmPush(edx);
|
|
|
| ExternalReference has_pending_message =
|
| ExternalReference::address_of_has_pending_message(isolate());
|
| __ mov(edx, Operand::StaticVariable(has_pending_message));
|
| __ SmiTag(edx);
|
| - __ push(edx);
|
| + AsmPush(edx);
|
|
|
| ExternalReference pending_message_script =
|
| ExternalReference::address_of_pending_message_script(isolate());
|
| __ mov(edx, Operand::StaticVariable(pending_message_script));
|
| - __ push(edx);
|
| + AsmPush(edx);
|
| }
|
|
|
|
|
| void FullCodeGenerator::ExitFinallyBlock() {
|
| ASSERT(!result_register().is(edx));
|
| // Restore pending message from stack.
|
| - __ pop(edx);
|
| + AsmPop(edx);
|
| ExternalReference pending_message_script =
|
| ExternalReference::address_of_pending_message_script(isolate());
|
| __ mov(Operand::StaticVariable(pending_message_script), edx);
|
|
|
| - __ pop(edx);
|
| + AsmPop(edx);
|
| __ SmiUntag(edx);
|
| ExternalReference has_pending_message =
|
| ExternalReference::address_of_has_pending_message(isolate());
|
| __ mov(Operand::StaticVariable(has_pending_message), edx);
|
|
|
| - __ pop(edx);
|
| + AsmPop(edx);
|
| ExternalReference pending_message_obj =
|
| ExternalReference::address_of_pending_message_obj(isolate());
|
| __ mov(Operand::StaticVariable(pending_message_obj), edx);
|
|
|
| // Restore result register from stack.
|
| - __ pop(result_register());
|
| + AsmPop(result_register());
|
|
|
| // Uncook return address.
|
| - __ pop(edx);
|
| + AsmPop(edx);
|
| __ SmiUntag(edx);
|
| __ add(edx, Immediate(masm_->CodeObject()));
|
| __ jmp(edx);
|
| }
|
|
|
|
|
| +#if defined(VERIFY_STACK_HEIGHT)
|
| +void FullCodeGenerator::AddStackHeightVerifier() {
|
| + // Insert code that verifies at runtime that our stack height calculation
|
| + // is correct
|
| + Label L;
|
| + __ push(eax);
|
| + __ pushfd();
|
| + __ mov(eax, ebp);
|
| + __ sub(eax, esp);
|
| + const int stack_diff = 4; // We need to account for the pushed stuff
|
| + __ cmp(eax, (stack_height_.get() + stack_diff) * kPointerSize);
|
| + __ j(equal, &L);
|
| + __ int3();
|
| + __ bind(&L);
|
| + __ popfd();
|
| + __ pop(eax);
|
| +}
|
| +#endif // defined(VERIFY_STACK_HEIGHT)
|
| +
|
| +void FullCodeGenerator::AsmPush(const Operand& op) {
|
| + masm()->push(op);
|
| + UpdateStackHeight(1);
|
| +}
|
| +
|
| +
|
| #undef __
|
|
|
| #define __ ACCESS_MASM(masm())
|
| @@ -4703,13 +4767,13 @@ FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
|
| // code, we can restore it directly from there for the finally code
|
| // rather than iteratively unwinding contexts via their previous
|
| // links.
|
| - __ Drop(*stack_depth); // Down to the handler block.
|
| + codegen()->AsmDrop(*stack_depth); // Down to the handler block.
|
| if (*context_length > 0) {
|
| // Restore the context to its dedicated register and the stack.
|
| __ mov(esi, Operand(esp, StackHandlerConstants::kContextOffset));
|
| __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
|
| }
|
| - __ PopTryHandler();
|
| + codegen()->AsmPopTryHandler();
|
| __ call(finally_entry_);
|
|
|
| *stack_depth = 0;
|
| @@ -4719,7 +4783,6 @@ FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
|
|
|
| #undef __
|
|
|
| -
|
| static const byte kJnsInstruction = 0x79;
|
| static const byte kJnsOffset = 0x11;
|
| static const byte kNopByteOne = 0x66;
|
|
|