2015-08-03 10:42:16 +00:00
|
|
|
// Copyright 2014 the V8 project authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
|
|
|
#include "src/v8.h"
|
|
|
|
|
|
|
|
#include "src/interpreter/bytecode-array-builder.h"
|
2015-09-24 15:20:47 +00:00
|
|
|
#include "src/interpreter/bytecode-array-iterator.h"
|
2016-01-14 13:43:14 +00:00
|
|
|
#include "src/interpreter/bytecode-register-allocator.h"
|
2015-08-13 11:27:54 +00:00
|
|
|
#include "test/unittests/test-utils.h"
|
2015-08-03 10:42:16 +00:00
|
|
|
|
2015-08-13 11:27:54 +00:00
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
namespace interpreter {
|
2015-08-03 10:42:16 +00:00
|
|
|
|
2015-08-28 15:40:52 +00:00
|
|
|
class BytecodeArrayBuilderTest : public TestWithIsolateAndZone {
|
2015-08-13 11:27:54 +00:00
|
|
|
public:
|
|
|
|
BytecodeArrayBuilderTest() {}
|
|
|
|
~BytecodeArrayBuilderTest() override {}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
|
2016-02-02 14:31:35 +00:00
|
|
|
BytecodeArrayBuilder builder(isolate(), zone(), 0, 1, 131);
|
2016-05-12 19:18:07 +00:00
|
|
|
Factory* factory = isolate()->factory();
|
2015-08-03 10:42:16 +00:00
|
|
|
|
2016-01-19 16:06:10 +00:00
|
|
|
CHECK_EQ(builder.locals_count(), 131);
|
2015-10-16 15:29:07 +00:00
|
|
|
CHECK_EQ(builder.context_count(), 1);
|
2016-01-19 16:06:10 +00:00
|
|
|
CHECK_EQ(builder.fixed_register_count(), 132);
|
2015-08-03 10:42:16 +00:00
|
|
|
|
2016-05-12 19:18:07 +00:00
|
|
|
Register reg(0);
|
|
|
|
Register other(reg.index() + 1);
|
|
|
|
Register wide(128);
|
|
|
|
|
[runtime] Optimize and unify rest parameters.
Replace the somewhat awkward RestParamAccessStub, which would always
call into the runtime anyway with a proper FastNewRestParameterStub,
which is basically based on the code that was already there for strict
arguments object materialization. But for rest parameters we could
optimize even further (leading to 8-10x improvements for functions with
rest parameters), by fixing the internal formal parameter count:
Every SharedFunctionInfo has a formal_parameter_count field, which
specifies the number of formal parameters, and is used to decide whether
we need to create an arguments adaptor frame when calling a function
(i.e. if there's a mismatch between the actual and expected parameters).
Previously the formal_parameter_count included the rest parameter, which
was sort of unfortunate, as that meant that calling a function with only
the non-rest parameters still required an arguments adaptor (plus some
other oddities). Now with this CL we fix, so that we do no longer
include the rest parameter in that count. Thereby checking for rest
parameters is very efficient, as we only need to check whether there is
an arguments adaptor frame, and if not create an empty array, otherwise
check whether the arguments adaptor frame has more parameters than
specified by the formal_parameter_count.
The FastNewRestParameterStub is written in a way that it can be directly
used by Ignition as well, and with some tweaks to the TurboFan backends
and the CodeStubAssembler, we should be able to rewrite it as
TurboFanCodeStub in the near future.
Drive-by-fix: Refactor and unify the CreateArgumentsType which was
different in TurboFan and Ignition; now we have a single enum class
which is used in both TurboFan and Ignition.
R=jarin@chromium.org, rmcilroy@chromium.org
TBR=rossberg@chromium.org
BUG=v8:2159
LOG=n
Review URL: https://codereview.chromium.org/1676883002
Cr-Commit-Position: refs/heads/master@{#33809}
2016-02-08 10:08:21 +00:00
|
|
|
// Emit argument creation operations.
|
2016-02-04 10:02:34 +00:00
|
|
|
builder.CreateArguments(CreateArgumentsType::kMappedArguments)
|
|
|
|
.CreateArguments(CreateArgumentsType::kUnmappedArguments)
|
[runtime] Optimize and unify rest parameters.
Replace the somewhat awkward RestParamAccessStub, which would always
call into the runtime anyway with a proper FastNewRestParameterStub,
which is basically based on the code that was already there for strict
arguments object materialization. But for rest parameters we could
optimize even further (leading to 8-10x improvements for functions with
rest parameters), by fixing the internal formal parameter count:
Every SharedFunctionInfo has a formal_parameter_count field, which
specifies the number of formal parameters, and is used to decide whether
we need to create an arguments adaptor frame when calling a function
(i.e. if there's a mismatch between the actual and expected parameters).
Previously the formal_parameter_count included the rest parameter, which
was sort of unfortunate, as that meant that calling a function with only
the non-rest parameters still required an arguments adaptor (plus some
other oddities). Now with this CL we fix, so that we do no longer
include the rest parameter in that count. Thereby checking for rest
parameters is very efficient, as we only need to check whether there is
an arguments adaptor frame, and if not create an empty array, otherwise
check whether the arguments adaptor frame has more parameters than
specified by the formal_parameter_count.
The FastNewRestParameterStub is written in a way that it can be directly
used by Ignition as well, and with some tweaks to the TurboFan backends
and the CodeStubAssembler, we should be able to rewrite it as
TurboFanCodeStub in the near future.
Drive-by-fix: Refactor and unify the CreateArgumentsType which was
different in TurboFan and Ignition; now we have a single enum class
which is used in both TurboFan and Ignition.
R=jarin@chromium.org, rmcilroy@chromium.org
TBR=rossberg@chromium.org
BUG=v8:2159
LOG=n
Review URL: https://codereview.chromium.org/1676883002
Cr-Commit-Position: refs/heads/master@{#33809}
2016-02-08 10:08:21 +00:00
|
|
|
.CreateArguments(CreateArgumentsType::kRestParameter);
|
2016-02-04 10:02:34 +00:00
|
|
|
|
2015-08-03 10:42:16 +00:00
|
|
|
// Emit constant loads.
|
|
|
|
builder.LoadLiteral(Smi::FromInt(0))
|
2016-05-12 19:18:07 +00:00
|
|
|
.StoreAccumulatorInRegister(reg)
|
2015-08-03 10:42:16 +00:00
|
|
|
.LoadLiteral(Smi::FromInt(8))
|
2016-05-12 19:18:07 +00:00
|
|
|
.StoreAccumulatorInRegister(reg)
|
2015-08-28 15:40:52 +00:00
|
|
|
.LoadLiteral(Smi::FromInt(10000000))
|
2016-05-12 19:18:07 +00:00
|
|
|
.StoreAccumulatorInRegister(reg)
|
|
|
|
.LoadLiteral(factory->NewStringFromStaticChars("A constant"))
|
|
|
|
.StoreAccumulatorInRegister(reg)
|
2015-08-03 10:42:16 +00:00
|
|
|
.LoadUndefined()
|
2016-05-25 09:55:26 +00:00
|
|
|
.Debugger() // Prevent peephole optimization LdaNull, Star -> LdrNull.
|
2015-08-03 10:42:16 +00:00
|
|
|
.LoadNull()
|
2016-05-12 19:18:07 +00:00
|
|
|
.StoreAccumulatorInRegister(reg)
|
2015-08-03 10:42:16 +00:00
|
|
|
.LoadTheHole()
|
2016-05-12 19:18:07 +00:00
|
|
|
.StoreAccumulatorInRegister(reg)
|
2015-08-03 10:42:16 +00:00
|
|
|
.LoadTrue()
|
2016-05-12 19:18:07 +00:00
|
|
|
.StoreAccumulatorInRegister(reg)
|
|
|
|
.LoadFalse()
|
|
|
|
.StoreAccumulatorInRegister(wide);
|
2015-08-03 10:42:16 +00:00
|
|
|
|
2016-05-27 15:57:35 +00:00
|
|
|
// Emit Ldar and Star taking care to foil the register optimizer.
|
2016-05-12 19:18:07 +00:00
|
|
|
builder.StackCheck(0)
|
|
|
|
.LoadAccumulatorWithRegister(other)
|
2016-05-27 15:57:35 +00:00
|
|
|
.BinaryOperation(Token::ADD, reg)
|
2016-05-12 19:18:07 +00:00
|
|
|
.StoreAccumulatorInRegister(reg)
|
2016-05-27 15:57:35 +00:00
|
|
|
.LoadNull();
|
2015-08-03 10:42:16 +00:00
|
|
|
|
2015-11-20 11:17:10 +00:00
|
|
|
// Emit register-register transfer.
|
|
|
|
builder.MoveRegister(reg, other);
|
2016-01-19 16:06:10 +00:00
|
|
|
builder.MoveRegister(reg, wide);
|
2016-01-04 17:38:17 +00:00
|
|
|
|
2015-10-22 14:55:32 +00:00
|
|
|
// Emit global load / store operations.
|
2015-12-23 09:34:00 +00:00
|
|
|
Handle<String> name = factory->NewStringFromStaticChars("var_name");
|
2016-02-17 10:30:10 +00:00
|
|
|
builder.LoadGlobal(name, 1, TypeofMode::NOT_INSIDE_TYPEOF)
|
|
|
|
.LoadGlobal(name, 1, TypeofMode::INSIDE_TYPEOF)
|
2015-12-23 09:34:00 +00:00
|
|
|
.StoreGlobal(name, 1, LanguageMode::SLOPPY)
|
|
|
|
.StoreGlobal(name, 1, LanguageMode::STRICT);
|
2015-10-30 11:17:07 +00:00
|
|
|
|
2015-10-13 13:09:48 +00:00
|
|
|
// Emit context operations.
|
2016-01-11 16:37:53 +00:00
|
|
|
builder.PushContext(reg)
|
|
|
|
.PopContext(reg)
|
|
|
|
.LoadContextSlot(reg, 1)
|
|
|
|
.StoreContextSlot(reg, 1);
|
2015-09-24 11:48:22 +00:00
|
|
|
|
2015-09-09 15:46:04 +00:00
|
|
|
// Emit load / store property operations.
|
2016-02-17 10:30:10 +00:00
|
|
|
builder.LoadNamedProperty(reg, name, 0)
|
|
|
|
.LoadKeyedProperty(reg, 0)
|
2015-12-23 09:34:00 +00:00
|
|
|
.StoreNamedProperty(reg, name, 0, LanguageMode::SLOPPY)
|
2015-10-07 07:54:07 +00:00
|
|
|
.StoreKeyedProperty(reg, reg, 0, LanguageMode::SLOPPY)
|
2015-12-23 09:34:00 +00:00
|
|
|
.StoreNamedProperty(reg, name, 0, LanguageMode::STRICT)
|
2015-10-14 13:19:49 +00:00
|
|
|
.StoreKeyedProperty(reg, reg, 0, LanguageMode::STRICT);
|
2015-09-02 13:03:06 +00:00
|
|
|
|
2015-12-16 17:24:20 +00:00
|
|
|
// Emit load / store lookup slots.
|
|
|
|
builder.LoadLookupSlot(name, TypeofMode::NOT_INSIDE_TYPEOF)
|
|
|
|
.LoadLookupSlot(name, TypeofMode::INSIDE_TYPEOF)
|
|
|
|
.StoreLookupSlot(name, LanguageMode::SLOPPY)
|
|
|
|
.StoreLookupSlot(name, LanguageMode::STRICT);
|
|
|
|
|
|
|
|
// Emit closure operations.
|
2015-11-26 14:33:06 +00:00
|
|
|
Handle<SharedFunctionInfo> shared_info = factory->NewSharedFunctionInfo(
|
|
|
|
factory->NewStringFromStaticChars("function_a"), MaybeHandle<Code>(),
|
|
|
|
false);
|
|
|
|
builder.CreateClosure(shared_info, NOT_TENURED);
|
2015-10-13 09:39:55 +00:00
|
|
|
|
2015-12-09 11:53:07 +00:00
|
|
|
// Emit literal creation operations.
|
|
|
|
builder.CreateRegExpLiteral(factory->NewStringFromStaticChars("a"), 0, 0)
|
|
|
|
.CreateArrayLiteral(factory->NewFixedArray(1), 0, 0)
|
|
|
|
.CreateObjectLiteral(factory->NewFixedArray(1), 0, 0);
|
2015-10-13 14:00:40 +00:00
|
|
|
|
2015-09-14 10:05:18 +00:00
|
|
|
// Call operations.
|
2016-02-24 15:15:02 +00:00
|
|
|
builder.Call(reg, other, 1, 0)
|
|
|
|
.Call(reg, wide, 1, 0)
|
|
|
|
.TailCall(reg, other, 1, 0)
|
|
|
|
.TailCall(reg, wide, 1, 0)
|
2015-11-04 09:21:26 +00:00
|
|
|
.CallRuntime(Runtime::kIsArray, reg, 1)
|
2016-01-19 16:06:10 +00:00
|
|
|
.CallRuntime(Runtime::kIsArray, wide, 1)
|
2016-02-11 06:24:04 +00:00
|
|
|
.CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, reg, 1, other)
|
|
|
|
.CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, wide, 1, other)
|
2016-01-19 16:06:10 +00:00
|
|
|
.CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, reg, 1)
|
|
|
|
.CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, wide, 1);
|
2015-09-14 10:05:18 +00:00
|
|
|
|
2015-09-24 15:20:47 +00:00
|
|
|
// Emit binary operator invocations.
|
2016-02-16 13:54:51 +00:00
|
|
|
builder.BinaryOperation(Token::Value::ADD, reg)
|
|
|
|
.BinaryOperation(Token::Value::SUB, reg)
|
|
|
|
.BinaryOperation(Token::Value::MUL, reg)
|
|
|
|
.BinaryOperation(Token::Value::DIV, reg)
|
|
|
|
.BinaryOperation(Token::Value::MOD, reg);
|
2015-08-03 10:42:16 +00:00
|
|
|
|
2015-10-12 13:35:57 +00:00
|
|
|
// Emit bitwise operator invocations
|
2016-02-16 13:54:51 +00:00
|
|
|
builder.BinaryOperation(Token::Value::BIT_OR, reg)
|
|
|
|
.BinaryOperation(Token::Value::BIT_XOR, reg)
|
|
|
|
.BinaryOperation(Token::Value::BIT_AND, reg);
|
2015-10-12 13:35:57 +00:00
|
|
|
|
2015-10-12 10:45:19 +00:00
|
|
|
// Emit shift operator invocations
|
2016-02-16 13:54:51 +00:00
|
|
|
builder.BinaryOperation(Token::Value::SHL, reg)
|
|
|
|
.BinaryOperation(Token::Value::SAR, reg)
|
|
|
|
.BinaryOperation(Token::Value::SHR, reg);
|
2015-10-12 10:45:19 +00:00
|
|
|
|
2015-10-22 20:40:20 +00:00
|
|
|
// Emit count operatior invocations
|
2016-02-16 13:54:51 +00:00
|
|
|
builder.CountOperation(Token::Value::ADD).CountOperation(Token::Value::SUB);
|
2015-10-22 20:40:20 +00:00
|
|
|
|
2015-10-06 14:15:09 +00:00
|
|
|
// Emit unary operator invocations.
|
2016-05-17 20:39:45 +00:00
|
|
|
builder
|
|
|
|
.LogicalNot() // ToBooleanLogicalNot
|
|
|
|
.LogicalNot() // non-ToBoolean LogicalNot
|
|
|
|
.TypeOf();
|
2015-10-06 14:15:09 +00:00
|
|
|
|
2015-10-28 09:49:20 +00:00
|
|
|
// Emit delete
|
2016-02-11 16:14:35 +00:00
|
|
|
builder.Delete(reg, LanguageMode::SLOPPY).Delete(reg, LanguageMode::STRICT);
|
2015-10-22 20:40:20 +00:00
|
|
|
|
2015-10-15 16:46:16 +00:00
|
|
|
// Emit new.
|
|
|
|
builder.New(reg, reg, 0);
|
2016-01-19 16:06:10 +00:00
|
|
|
builder.New(wide, wide, 0);
|
2015-10-15 16:46:16 +00:00
|
|
|
|
2015-09-24 15:20:47 +00:00
|
|
|
// Emit test operator invocations.
|
2016-02-16 13:54:51 +00:00
|
|
|
builder.CompareOperation(Token::Value::EQ, reg)
|
|
|
|
.CompareOperation(Token::Value::NE, reg)
|
|
|
|
.CompareOperation(Token::Value::EQ_STRICT, reg)
|
|
|
|
.CompareOperation(Token::Value::LT, reg)
|
|
|
|
.CompareOperation(Token::Value::GT, reg)
|
|
|
|
.CompareOperation(Token::Value::LTE, reg)
|
|
|
|
.CompareOperation(Token::Value::GTE, reg)
|
|
|
|
.CompareOperation(Token::Value::INSTANCEOF, reg)
|
|
|
|
.CompareOperation(Token::Value::IN, reg);
|
2015-09-24 15:20:47 +00:00
|
|
|
|
|
|
|
// Emit cast operator invocations.
|
2015-10-22 20:40:20 +00:00
|
|
|
builder.CastAccumulatorToNumber()
|
2015-10-29 12:06:00 +00:00
|
|
|
.CastAccumulatorToJSObject()
|
2015-10-14 10:10:01 +00:00
|
|
|
.CastAccumulatorToName();
|
2015-09-24 15:20:47 +00:00
|
|
|
|
2015-08-03 10:42:16 +00:00
|
|
|
// Emit control flow. Return must be the last instruction.
|
2015-09-24 15:20:47 +00:00
|
|
|
BytecodeLabel start;
|
|
|
|
builder.Bind(&start);
|
|
|
|
// Short jumps with Imm8 operands
|
2016-02-08 14:14:35 +00:00
|
|
|
builder.Jump(&start)
|
|
|
|
.JumpIfNull(&start)
|
|
|
|
.JumpIfUndefined(&start)
|
|
|
|
.JumpIfNotHole(&start);
|
2016-02-12 15:24:01 +00:00
|
|
|
|
2016-03-21 17:08:21 +00:00
|
|
|
// Longer jumps with constant operands
|
|
|
|
BytecodeLabel end[8];
|
|
|
|
builder.Jump(&end[0])
|
|
|
|
.LoadTrue()
|
|
|
|
.JumpIfTrue(&end[1])
|
|
|
|
.LoadTrue()
|
|
|
|
.JumpIfFalse(&end[2])
|
|
|
|
.LoadLiteral(Smi::FromInt(0))
|
|
|
|
.JumpIfTrue(&end[3])
|
|
|
|
.LoadLiteral(Smi::FromInt(0))
|
|
|
|
.JumpIfFalse(&end[4])
|
|
|
|
.JumpIfNull(&end[5])
|
|
|
|
.JumpIfUndefined(&end[6])
|
|
|
|
.JumpIfNotHole(&end[7]);
|
|
|
|
|
2015-10-30 16:48:18 +00:00
|
|
|
// Perform an operation that returns boolean value to
|
|
|
|
// generate JumpIfTrue/False
|
2016-02-16 13:54:51 +00:00
|
|
|
builder.CompareOperation(Token::Value::EQ, reg)
|
2015-10-30 16:48:18 +00:00
|
|
|
.JumpIfTrue(&start)
|
2016-02-16 13:54:51 +00:00
|
|
|
.CompareOperation(Token::Value::EQ, reg)
|
2015-10-30 16:48:18 +00:00
|
|
|
.JumpIfFalse(&start);
|
|
|
|
// Perform an operation that returns a non-boolean operation to
|
|
|
|
// generate JumpIfToBooleanTrue/False.
|
2016-02-16 13:54:51 +00:00
|
|
|
builder.BinaryOperation(Token::Value::ADD, reg)
|
2015-10-30 16:48:18 +00:00
|
|
|
.JumpIfTrue(&start)
|
2016-02-16 13:54:51 +00:00
|
|
|
.BinaryOperation(Token::Value::ADD, reg)
|
2015-10-30 16:48:18 +00:00
|
|
|
.JumpIfFalse(&start);
|
2015-09-24 15:20:47 +00:00
|
|
|
// Insert dummy ops to force longer jumps
|
|
|
|
for (int i = 0; i < 128; i++) {
|
|
|
|
builder.LoadTrue();
|
|
|
|
}
|
|
|
|
// Longer jumps requiring Constant operand
|
2016-02-12 15:24:01 +00:00
|
|
|
builder.Jump(&start).JumpIfNull(&start).JumpIfUndefined(&start).JumpIfNotHole(
|
|
|
|
&start);
|
2015-10-30 16:48:18 +00:00
|
|
|
// Perform an operation that returns boolean value to
|
|
|
|
// generate JumpIfTrue/False
|
2016-02-16 13:54:51 +00:00
|
|
|
builder.CompareOperation(Token::Value::EQ, reg)
|
2015-10-30 16:48:18 +00:00
|
|
|
.JumpIfTrue(&start)
|
2016-02-16 13:54:51 +00:00
|
|
|
.CompareOperation(Token::Value::EQ, reg)
|
2015-10-30 16:48:18 +00:00
|
|
|
.JumpIfFalse(&start);
|
|
|
|
// Perform an operation that returns a non-boolean operation to
|
|
|
|
// generate JumpIfToBooleanTrue/False.
|
2016-02-16 13:54:51 +00:00
|
|
|
builder.BinaryOperation(Token::Value::ADD, reg)
|
2015-10-30 16:48:18 +00:00
|
|
|
.JumpIfTrue(&start)
|
2016-02-16 13:54:51 +00:00
|
|
|
.BinaryOperation(Token::Value::ADD, reg)
|
2015-10-30 16:48:18 +00:00
|
|
|
.JumpIfFalse(&start);
|
2015-10-19 10:59:00 +00:00
|
|
|
|
2016-02-04 12:33:13 +00:00
|
|
|
// Emit stack check bytecode.
|
2016-04-28 13:16:48 +00:00
|
|
|
builder.StackCheck(0);
|
2016-02-04 12:33:13 +00:00
|
|
|
|
2016-01-22 16:25:46 +00:00
|
|
|
// Emit throw and re-throw in it's own basic block so that the rest of the
|
|
|
|
// code isn't omitted due to being dead.
|
2015-11-03 11:27:54 +00:00
|
|
|
BytecodeLabel after_throw;
|
2016-01-19 16:06:10 +00:00
|
|
|
builder.Jump(&after_throw).Throw().Bind(&after_throw);
|
2016-01-22 16:25:46 +00:00
|
|
|
BytecodeLabel after_rethrow;
|
|
|
|
builder.Jump(&after_rethrow).ReThrow().Bind(&after_rethrow);
|
2015-10-19 10:59:00 +00:00
|
|
|
|
2016-01-18 12:39:18 +00:00
|
|
|
builder.ForInPrepare(reg)
|
2015-12-21 13:30:47 +00:00
|
|
|
.ForInDone(reg, reg)
|
2016-03-01 13:55:48 +00:00
|
|
|
.ForInNext(reg, reg, reg, 1)
|
2015-12-21 13:30:47 +00:00
|
|
|
.ForInStep(reg);
|
2016-01-19 16:06:10 +00:00
|
|
|
builder.ForInPrepare(wide)
|
|
|
|
.ForInDone(reg, other)
|
2016-03-01 13:55:48 +00:00
|
|
|
.ForInNext(wide, wide, wide, 1024)
|
2016-01-19 16:06:10 +00:00
|
|
|
.ForInStep(reg);
|
2015-10-29 12:06:00 +00:00
|
|
|
|
2015-10-30 11:17:07 +00:00
|
|
|
// Wide constant pool loads
|
|
|
|
for (int i = 0; i < 256; i++) {
|
|
|
|
// Emit junk in constant pool to force wide constant pool index.
|
2015-12-23 09:34:00 +00:00
|
|
|
builder.LoadLiteral(factory->NewNumber(2.5321 + i));
|
2015-10-30 11:17:07 +00:00
|
|
|
}
|
|
|
|
builder.LoadLiteral(Smi::FromInt(20000000));
|
2015-12-23 09:34:00 +00:00
|
|
|
Handle<String> wide_name = factory->NewStringFromStaticChars("var_wide_name");
|
|
|
|
|
|
|
|
// Emit wide global load / store operations.
|
2016-02-17 10:30:10 +00:00
|
|
|
builder.LoadGlobal(name, 1024, TypeofMode::NOT_INSIDE_TYPEOF)
|
2016-03-21 17:08:21 +00:00
|
|
|
.LoadGlobal(name, 1024, TypeofMode::INSIDE_TYPEOF)
|
2016-02-17 10:30:10 +00:00
|
|
|
.LoadGlobal(name, 1024, TypeofMode::INSIDE_TYPEOF)
|
2015-12-23 09:34:00 +00:00
|
|
|
.StoreGlobal(name, 1024, LanguageMode::SLOPPY)
|
|
|
|
.StoreGlobal(wide_name, 1, LanguageMode::STRICT);
|
|
|
|
|
2016-03-21 17:08:21 +00:00
|
|
|
// Emit extra wide global load.
|
|
|
|
builder.LoadGlobal(name, 1024 * 1024, TypeofMode::NOT_INSIDE_TYPEOF);
|
|
|
|
|
2015-12-23 09:34:00 +00:00
|
|
|
// Emit wide load / store property operations.
|
2016-02-17 10:30:10 +00:00
|
|
|
builder.LoadNamedProperty(reg, wide_name, 0)
|
|
|
|
.LoadKeyedProperty(reg, 2056)
|
2015-12-23 09:34:00 +00:00
|
|
|
.StoreNamedProperty(reg, wide_name, 0, LanguageMode::SLOPPY)
|
|
|
|
.StoreKeyedProperty(reg, reg, 2056, LanguageMode::SLOPPY)
|
|
|
|
.StoreNamedProperty(reg, wide_name, 0, LanguageMode::STRICT)
|
|
|
|
.StoreKeyedProperty(reg, reg, 2056, LanguageMode::STRICT);
|
2015-10-30 11:17:07 +00:00
|
|
|
|
2016-01-11 16:37:53 +00:00
|
|
|
// Emit wide context operations.
|
2016-01-19 16:06:10 +00:00
|
|
|
builder.LoadContextSlot(reg, 1024).StoreContextSlot(reg, 1024);
|
2016-01-11 16:37:53 +00:00
|
|
|
|
2016-01-05 11:36:26 +00:00
|
|
|
// Emit wide load / store lookup slots.
|
|
|
|
builder.LoadLookupSlot(wide_name, TypeofMode::NOT_INSIDE_TYPEOF)
|
|
|
|
.LoadLookupSlot(wide_name, TypeofMode::INSIDE_TYPEOF)
|
|
|
|
.StoreLookupSlot(wide_name, LanguageMode::SLOPPY)
|
|
|
|
.StoreLookupSlot(wide_name, LanguageMode::STRICT);
|
|
|
|
|
2015-11-26 14:33:06 +00:00
|
|
|
// CreateClosureWide
|
|
|
|
Handle<SharedFunctionInfo> shared_info2 = factory->NewSharedFunctionInfo(
|
|
|
|
factory->NewStringFromStaticChars("function_b"), MaybeHandle<Code>(),
|
|
|
|
false);
|
|
|
|
builder.CreateClosure(shared_info2, NOT_TENURED);
|
|
|
|
|
2015-12-09 11:53:07 +00:00
|
|
|
// Emit wide variant of literal creation operations.
|
|
|
|
builder.CreateRegExpLiteral(factory->NewStringFromStaticChars("wide_literal"),
|
|
|
|
0, 0)
|
|
|
|
.CreateArrayLiteral(factory->NewFixedArray(2), 0, 0)
|
|
|
|
.CreateObjectLiteral(factory->NewFixedArray(2), 0, 0);
|
|
|
|
|
2016-01-05 19:08:11 +00:00
|
|
|
// Longer jumps requiring ConstantWide operand
|
2016-02-12 15:24:01 +00:00
|
|
|
builder.Jump(&start).JumpIfNull(&start).JumpIfUndefined(&start).JumpIfNotHole(
|
|
|
|
&start);
|
2016-05-27 15:57:35 +00:00
|
|
|
|
2016-01-05 19:08:11 +00:00
|
|
|
// Perform an operation that returns boolean value to
|
|
|
|
// generate JumpIfTrue/False
|
2016-02-16 13:54:51 +00:00
|
|
|
builder.CompareOperation(Token::Value::EQ, reg)
|
2016-01-05 19:08:11 +00:00
|
|
|
.JumpIfTrue(&start)
|
2016-02-16 13:54:51 +00:00
|
|
|
.CompareOperation(Token::Value::EQ, reg)
|
2016-01-05 19:08:11 +00:00
|
|
|
.JumpIfFalse(&start);
|
2016-05-27 15:57:35 +00:00
|
|
|
|
2016-01-05 19:08:11 +00:00
|
|
|
// Perform an operation that returns a non-boolean operation to
|
|
|
|
// generate JumpIfToBooleanTrue/False.
|
2016-02-16 13:54:51 +00:00
|
|
|
builder.BinaryOperation(Token::Value::ADD, reg)
|
2016-01-05 19:08:11 +00:00
|
|
|
.JumpIfTrue(&start)
|
2016-02-16 13:54:51 +00:00
|
|
|
.BinaryOperation(Token::Value::ADD, reg)
|
2016-01-05 19:08:11 +00:00
|
|
|
.JumpIfFalse(&start);
|
|
|
|
|
2016-04-22 09:17:58 +00:00
|
|
|
// Emit generator operations
|
|
|
|
builder.SuspendGenerator(reg)
|
|
|
|
.ResumeGenerator(reg);
|
|
|
|
|
2016-03-22 11:35:09 +00:00
|
|
|
// Intrinsics handled by the interpreter.
|
|
|
|
builder.CallRuntime(Runtime::kInlineIsArray, reg, 1)
|
|
|
|
.CallRuntime(Runtime::kInlineIsArray, wide, 1);
|
|
|
|
|
2016-02-04 15:06:25 +00:00
|
|
|
builder.Debugger();
|
2016-03-21 17:08:21 +00:00
|
|
|
for (size_t i = 0; i < arraysize(end); i++) {
|
|
|
|
builder.Bind(&end[i]);
|
|
|
|
}
|
2015-08-03 10:42:16 +00:00
|
|
|
builder.Return();
|
|
|
|
|
|
|
|
// Generate BytecodeArray.
|
|
|
|
Handle<BytecodeArray> the_array = builder.ToBytecodeArray();
|
2015-10-16 15:29:07 +00:00
|
|
|
CHECK_EQ(the_array->frame_size(),
|
2016-03-21 17:08:21 +00:00
|
|
|
builder.fixed_and_temporary_register_count() * kPointerSize);
|
2015-08-03 10:42:16 +00:00
|
|
|
|
|
|
|
// Build scorecard of bytecodes encountered in the BytecodeArray.
|
|
|
|
std::vector<int> scorecard(Bytecodes::ToByte(Bytecode::kLast) + 1);
|
2016-03-21 17:08:21 +00:00
|
|
|
|
2015-08-03 10:42:16 +00:00
|
|
|
Bytecode final_bytecode = Bytecode::kLdaZero;
|
2015-10-01 17:22:58 +00:00
|
|
|
int i = 0;
|
|
|
|
while (i < the_array->length()) {
|
2015-08-03 10:42:16 +00:00
|
|
|
uint8_t code = the_array->get(i);
|
|
|
|
scorecard[code] += 1;
|
|
|
|
final_bytecode = Bytecodes::FromByte(code);
|
2016-03-21 17:08:21 +00:00
|
|
|
OperandScale operand_scale = OperandScale::kSingle;
|
|
|
|
int prefix_offset = 0;
|
|
|
|
if (Bytecodes::IsPrefixScalingBytecode(final_bytecode)) {
|
|
|
|
operand_scale = Bytecodes::PrefixBytecodeToOperandScale(final_bytecode);
|
|
|
|
prefix_offset = 1;
|
|
|
|
code = the_array->get(i + 1);
|
|
|
|
final_bytecode = Bytecodes::FromByte(code);
|
|
|
|
}
|
|
|
|
i += prefix_offset + Bytecodes::Size(final_bytecode, operand_scale);
|
2015-08-03 10:42:16 +00:00
|
|
|
}
|
|
|
|
|
2016-03-21 17:08:21 +00:00
|
|
|
// Insert entry for illegal bytecode as this is never willingly emitted.
|
|
|
|
scorecard[Bytecodes::ToByte(Bytecode::kIllegal)] = 1;
|
|
|
|
|
2016-05-12 19:18:07 +00:00
|
|
|
// Insert entry for nop bytecode as this often gets optimized out.
|
|
|
|
scorecard[Bytecodes::ToByte(Bytecode::kNop)] = 1;
|
|
|
|
|
2016-05-25 09:55:26 +00:00
|
|
|
// Insert entries for bytecodes only emiited by peephole optimizer.
|
|
|
|
scorecard[Bytecodes::ToByte(Bytecode::kLdrNamedProperty)] = 1;
|
|
|
|
scorecard[Bytecodes::ToByte(Bytecode::kLdrKeyedProperty)] = 1;
|
|
|
|
scorecard[Bytecodes::ToByte(Bytecode::kLdrGlobal)] = 1;
|
|
|
|
scorecard[Bytecodes::ToByte(Bytecode::kLdrContextSlot)] = 1;
|
|
|
|
scorecard[Bytecodes::ToByte(Bytecode::kLdrUndefined)] = 1;
|
|
|
|
|
2015-08-03 10:42:16 +00:00
|
|
|
// Check return occurs at the end and only once in the BytecodeArray.
|
|
|
|
CHECK_EQ(final_bytecode, Bytecode::kReturn);
|
|
|
|
CHECK_EQ(scorecard[Bytecodes::ToByte(final_bytecode)], 1);
|
|
|
|
|
2016-02-22 13:16:46 +00:00
|
|
|
#define CHECK_BYTECODE_PRESENT(Name, ...) \
|
|
|
|
/* Check Bytecode is marked in scorecard, unless it's a debug break */ \
|
|
|
|
if (!Bytecodes::IsDebugBreak(Bytecode::k##Name)) { \
|
|
|
|
CHECK_GE(scorecard[Bytecodes::ToByte(Bytecode::k##Name)], 1); \
|
|
|
|
}
|
2015-08-03 10:42:16 +00:00
|
|
|
BYTECODE_LIST(CHECK_BYTECODE_PRESENT)
|
|
|
|
#undef CHECK_BYTECODE_PRESENT
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-13 11:27:54 +00:00
|
|
|
TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) {
|
2015-08-03 20:38:57 +00:00
|
|
|
for (int locals = 0; locals < 5; locals++) {
|
2015-10-16 15:29:07 +00:00
|
|
|
for (int contexts = 0; contexts < 4; contexts++) {
|
|
|
|
for (int temps = 0; temps < 3; temps++) {
|
2016-02-02 14:31:35 +00:00
|
|
|
BytecodeArrayBuilder builder(isolate(), zone(), 0, contexts, locals);
|
|
|
|
BytecodeRegisterAllocator temporaries(
|
|
|
|
zone(), builder.temporary_register_allocator());
|
2016-05-27 15:57:35 +00:00
|
|
|
for (int i = 0; i < locals + contexts; i++) {
|
|
|
|
builder.LoadLiteral(Smi::FromInt(0));
|
|
|
|
builder.StoreAccumulatorInRegister(Register(i));
|
|
|
|
}
|
2015-10-16 15:29:07 +00:00
|
|
|
for (int i = 0; i < temps; i++) {
|
2016-05-27 15:57:35 +00:00
|
|
|
builder.LoadLiteral(Smi::FromInt(0));
|
2015-10-21 15:28:55 +00:00
|
|
|
builder.StoreAccumulatorInRegister(temporaries.NewRegister());
|
2015-10-16 15:29:07 +00:00
|
|
|
}
|
2016-05-27 15:57:35 +00:00
|
|
|
if (temps > 0) {
|
|
|
|
// Ensure temporaries are used so not optimized away by the
|
|
|
|
// register optimizer.
|
|
|
|
builder.New(Register(locals + contexts), Register(locals + contexts),
|
|
|
|
static_cast<size_t>(temps));
|
|
|
|
}
|
2015-10-21 15:28:55 +00:00
|
|
|
builder.Return();
|
2015-10-16 15:29:07 +00:00
|
|
|
|
|
|
|
Handle<BytecodeArray> the_array = builder.ToBytecodeArray();
|
|
|
|
int total_registers = locals + contexts + temps;
|
|
|
|
CHECK_EQ(the_array->frame_size(), total_registers * kPointerSize);
|
2015-08-03 10:42:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-13 17:11:25 +00:00
|
|
|
TEST_F(BytecodeArrayBuilderTest, RegisterValues) {
|
|
|
|
int index = 1;
|
|
|
|
|
|
|
|
Register the_register(index);
|
|
|
|
CHECK_EQ(the_register.index(), index);
|
|
|
|
|
|
|
|
int actual_operand = the_register.ToOperand();
|
|
|
|
int actual_index = Register::FromOperand(actual_operand).index();
|
|
|
|
CHECK_EQ(actual_index, index);
|
|
|
|
}
|
|
|
|
|
2015-08-27 10:32:26 +00:00
|
|
|
|
|
|
|
TEST_F(BytecodeArrayBuilderTest, Parameters) {
|
2016-02-02 14:31:35 +00:00
|
|
|
BytecodeArrayBuilder builder(isolate(), zone(), 10, 0, 0);
|
2016-05-27 15:57:35 +00:00
|
|
|
|
2015-08-27 10:32:26 +00:00
|
|
|
Register param0(builder.Parameter(0));
|
|
|
|
Register param9(builder.Parameter(9));
|
|
|
|
CHECK_EQ(param9.index() - param0.index(), 9);
|
|
|
|
}
|
|
|
|
|
2015-08-28 15:40:52 +00:00
|
|
|
|
2015-10-21 15:28:55 +00:00
|
|
|
TEST_F(BytecodeArrayBuilderTest, RegisterType) {
|
2016-02-02 14:31:35 +00:00
|
|
|
BytecodeArrayBuilder builder(isolate(), zone(), 10, 0, 3);
|
|
|
|
BytecodeRegisterAllocator register_allocator(
|
|
|
|
zone(), builder.temporary_register_allocator());
|
2016-01-14 13:43:14 +00:00
|
|
|
Register temp0 = register_allocator.NewRegister();
|
2015-10-21 15:28:55 +00:00
|
|
|
Register param0(builder.Parameter(0));
|
|
|
|
Register param9(builder.Parameter(9));
|
2016-01-14 13:43:14 +00:00
|
|
|
Register temp1 = register_allocator.NewRegister();
|
2015-10-21 15:28:55 +00:00
|
|
|
Register reg0(0);
|
|
|
|
Register reg1(1);
|
|
|
|
Register reg2(2);
|
2016-01-14 13:43:14 +00:00
|
|
|
Register temp2 = register_allocator.NewRegister();
|
2015-10-21 15:28:55 +00:00
|
|
|
CHECK_EQ(builder.RegisterIsParameterOrLocal(temp0), false);
|
|
|
|
CHECK_EQ(builder.RegisterIsParameterOrLocal(temp1), false);
|
|
|
|
CHECK_EQ(builder.RegisterIsParameterOrLocal(temp2), false);
|
|
|
|
CHECK_EQ(builder.RegisterIsParameterOrLocal(param0), true);
|
|
|
|
CHECK_EQ(builder.RegisterIsParameterOrLocal(param9), true);
|
|
|
|
CHECK_EQ(builder.RegisterIsParameterOrLocal(reg0), true);
|
|
|
|
CHECK_EQ(builder.RegisterIsParameterOrLocal(reg1), true);
|
|
|
|
CHECK_EQ(builder.RegisterIsParameterOrLocal(reg2), true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-28 15:40:52 +00:00
|
|
|
TEST_F(BytecodeArrayBuilderTest, Constants) {
|
2016-02-02 14:31:35 +00:00
|
|
|
BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0);
|
2016-05-27 15:57:35 +00:00
|
|
|
|
2015-08-28 15:40:52 +00:00
|
|
|
Factory* factory = isolate()->factory();
|
|
|
|
Handle<HeapObject> heap_num_1 = factory->NewHeapNumber(3.14);
|
|
|
|
Handle<HeapObject> heap_num_2 = factory->NewHeapNumber(5.2);
|
|
|
|
Handle<Object> large_smi(Smi::FromInt(0x12345678), isolate());
|
|
|
|
Handle<HeapObject> heap_num_2_copy(*heap_num_2);
|
|
|
|
builder.LoadLiteral(heap_num_1)
|
|
|
|
.LoadLiteral(heap_num_2)
|
|
|
|
.LoadLiteral(large_smi)
|
|
|
|
.LoadLiteral(heap_num_1)
|
|
|
|
.LoadLiteral(heap_num_1)
|
2016-02-11 15:17:59 +00:00
|
|
|
.LoadLiteral(heap_num_2_copy)
|
|
|
|
.Return();
|
2015-08-28 15:40:52 +00:00
|
|
|
|
|
|
|
Handle<BytecodeArray> array = builder.ToBytecodeArray();
|
|
|
|
// Should only have one entry for each identical constant.
|
|
|
|
CHECK_EQ(array->constant_pool()->length(), 3);
|
|
|
|
}
|
|
|
|
|
2015-09-24 15:20:47 +00:00
|
|
|
|
|
|
|
TEST_F(BytecodeArrayBuilderTest, ForwardJumps) {
|
|
|
|
static const int kFarJumpDistance = 256;
|
|
|
|
|
2016-02-02 14:31:35 +00:00
|
|
|
BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 1);
|
2016-05-27 15:57:35 +00:00
|
|
|
|
2015-10-30 16:48:18 +00:00
|
|
|
Register reg(0);
|
|
|
|
BytecodeLabel far0, far1, far2, far3, far4;
|
|
|
|
BytecodeLabel near0, near1, near2, near3, near4;
|
2015-09-24 15:20:47 +00:00
|
|
|
|
|
|
|
builder.Jump(&near0)
|
2016-02-16 13:54:51 +00:00
|
|
|
.CompareOperation(Token::Value::EQ, reg)
|
2015-09-24 15:20:47 +00:00
|
|
|
.JumpIfTrue(&near1)
|
2016-02-16 13:54:51 +00:00
|
|
|
.CompareOperation(Token::Value::EQ, reg)
|
2015-09-24 15:20:47 +00:00
|
|
|
.JumpIfFalse(&near2)
|
2016-02-16 13:54:51 +00:00
|
|
|
.BinaryOperation(Token::Value::ADD, reg)
|
2015-10-30 16:48:18 +00:00
|
|
|
.JumpIfTrue(&near3)
|
2016-02-16 13:54:51 +00:00
|
|
|
.BinaryOperation(Token::Value::ADD, reg)
|
2015-10-30 16:48:18 +00:00
|
|
|
.JumpIfFalse(&near4)
|
2015-09-24 15:20:47 +00:00
|
|
|
.Bind(&near0)
|
|
|
|
.Bind(&near1)
|
|
|
|
.Bind(&near2)
|
2015-10-30 16:48:18 +00:00
|
|
|
.Bind(&near3)
|
|
|
|
.Bind(&near4)
|
2015-09-24 15:20:47 +00:00
|
|
|
.Jump(&far0)
|
2016-02-16 13:54:51 +00:00
|
|
|
.CompareOperation(Token::Value::EQ, reg)
|
2015-09-24 15:20:47 +00:00
|
|
|
.JumpIfTrue(&far1)
|
2016-02-16 13:54:51 +00:00
|
|
|
.CompareOperation(Token::Value::EQ, reg)
|
2015-10-30 16:48:18 +00:00
|
|
|
.JumpIfFalse(&far2)
|
2016-02-16 13:54:51 +00:00
|
|
|
.BinaryOperation(Token::Value::ADD, reg)
|
2015-10-30 16:48:18 +00:00
|
|
|
.JumpIfTrue(&far3)
|
2016-02-16 13:54:51 +00:00
|
|
|
.BinaryOperation(Token::Value::ADD, reg)
|
2015-10-30 16:48:18 +00:00
|
|
|
.JumpIfFalse(&far4);
|
|
|
|
for (int i = 0; i < kFarJumpDistance - 18; i++) {
|
2016-05-12 19:18:07 +00:00
|
|
|
builder.Debugger();
|
2015-09-24 15:20:47 +00:00
|
|
|
}
|
2015-10-30 16:48:18 +00:00
|
|
|
builder.Bind(&far0).Bind(&far1).Bind(&far2).Bind(&far3).Bind(&far4);
|
2015-09-24 15:20:47 +00:00
|
|
|
builder.Return();
|
|
|
|
|
|
|
|
Handle<BytecodeArray> array = builder.ToBytecodeArray();
|
2015-10-30 16:48:18 +00:00
|
|
|
DCHECK_EQ(array->length(), 36 + kFarJumpDistance - 18 + 1);
|
2015-09-24 15:20:47 +00:00
|
|
|
|
|
|
|
BytecodeArrayIterator iterator(array);
|
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
|
2015-10-30 16:48:18 +00:00
|
|
|
CHECK_EQ(iterator.GetImmediateOperand(0), 18);
|
|
|
|
iterator.Advance();
|
|
|
|
|
|
|
|
// Ignore compare operation.
|
2015-09-24 15:20:47 +00:00
|
|
|
iterator.Advance();
|
|
|
|
|
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue);
|
2015-10-30 16:48:18 +00:00
|
|
|
CHECK_EQ(iterator.GetImmediateOperand(0), 14);
|
|
|
|
iterator.Advance();
|
|
|
|
|
|
|
|
// Ignore compare operation.
|
2015-09-24 15:20:47 +00:00
|
|
|
iterator.Advance();
|
|
|
|
|
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse);
|
2015-10-30 16:48:18 +00:00
|
|
|
CHECK_EQ(iterator.GetImmediateOperand(0), 10);
|
|
|
|
iterator.Advance();
|
|
|
|
|
|
|
|
// Ignore add operation.
|
|
|
|
iterator.Advance();
|
|
|
|
|
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrue);
|
|
|
|
CHECK_EQ(iterator.GetImmediateOperand(0), 6);
|
|
|
|
iterator.Advance();
|
|
|
|
|
|
|
|
// Ignore add operation.
|
|
|
|
iterator.Advance();
|
|
|
|
|
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanFalse);
|
2015-10-01 17:22:58 +00:00
|
|
|
CHECK_EQ(iterator.GetImmediateOperand(0), 2);
|
2015-09-24 15:20:47 +00:00
|
|
|
iterator.Advance();
|
|
|
|
|
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpConstant);
|
|
|
|
CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
|
|
|
|
Smi::FromInt(kFarJumpDistance));
|
2015-10-30 16:48:18 +00:00
|
|
|
iterator.Advance();
|
|
|
|
|
|
|
|
// Ignore compare operation.
|
2015-09-24 15:20:47 +00:00
|
|
|
iterator.Advance();
|
|
|
|
|
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrueConstant);
|
|
|
|
CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
|
2015-10-30 16:48:18 +00:00
|
|
|
Smi::FromInt(kFarJumpDistance - 4));
|
|
|
|
iterator.Advance();
|
|
|
|
|
|
|
|
// Ignore compare operation.
|
2015-09-24 15:20:47 +00:00
|
|
|
iterator.Advance();
|
|
|
|
|
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalseConstant);
|
|
|
|
CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
|
2015-10-30 16:48:18 +00:00
|
|
|
Smi::FromInt(kFarJumpDistance - 8));
|
|
|
|
iterator.Advance();
|
|
|
|
|
|
|
|
// Ignore add operation.
|
|
|
|
iterator.Advance();
|
|
|
|
|
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrueConstant);
|
|
|
|
CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
|
|
|
|
Smi::FromInt(kFarJumpDistance - 12));
|
|
|
|
iterator.Advance();
|
|
|
|
|
|
|
|
// Ignore add operation.
|
|
|
|
iterator.Advance();
|
|
|
|
|
|
|
|
CHECK_EQ(iterator.current_bytecode(),
|
|
|
|
Bytecode::kJumpIfToBooleanFalseConstant);
|
|
|
|
CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
|
|
|
|
Smi::FromInt(kFarJumpDistance - 16));
|
2015-09-24 15:20:47 +00:00
|
|
|
iterator.Advance();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TEST_F(BytecodeArrayBuilderTest, BackwardJumps) {
|
2016-02-02 14:31:35 +00:00
|
|
|
BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 1);
|
2016-05-27 15:57:35 +00:00
|
|
|
|
2015-10-30 16:48:18 +00:00
|
|
|
Register reg(0);
|
2015-09-24 15:20:47 +00:00
|
|
|
|
2015-10-30 16:48:18 +00:00
|
|
|
BytecodeLabel label0, label1, label2, label3, label4;
|
2015-09-24 15:20:47 +00:00
|
|
|
builder.Bind(&label0)
|
|
|
|
.Jump(&label0)
|
|
|
|
.Bind(&label1)
|
2016-02-16 13:54:51 +00:00
|
|
|
.CompareOperation(Token::Value::EQ, reg)
|
2015-11-03 11:27:54 +00:00
|
|
|
.JumpIfTrue(&label1)
|
2015-09-24 15:20:47 +00:00
|
|
|
.Bind(&label2)
|
2016-02-16 13:54:51 +00:00
|
|
|
.CompareOperation(Token::Value::EQ, reg)
|
2015-10-30 16:48:18 +00:00
|
|
|
.JumpIfFalse(&label2)
|
|
|
|
.Bind(&label3)
|
2016-02-16 13:54:51 +00:00
|
|
|
.BinaryOperation(Token::Value::ADD, reg)
|
2015-11-03 11:27:54 +00:00
|
|
|
.JumpIfTrue(&label3)
|
2015-10-30 16:48:18 +00:00
|
|
|
.Bind(&label4)
|
2016-02-16 13:54:51 +00:00
|
|
|
.BinaryOperation(Token::Value::ADD, reg)
|
2015-10-30 16:48:18 +00:00
|
|
|
.JumpIfFalse(&label4);
|
2015-11-03 11:27:54 +00:00
|
|
|
for (int i = 0; i < 63; i++) {
|
2015-10-30 16:48:18 +00:00
|
|
|
builder.Jump(&label4);
|
2015-09-24 15:20:47 +00:00
|
|
|
}
|
2016-03-21 17:08:21 +00:00
|
|
|
|
|
|
|
// Add padding to force wide backwards jumps.
|
|
|
|
for (int i = 0; i < 256; i++) {
|
2016-05-12 19:18:07 +00:00
|
|
|
builder.Debugger();
|
2016-03-21 17:08:21 +00:00
|
|
|
}
|
|
|
|
|
2016-02-16 13:54:51 +00:00
|
|
|
builder.BinaryOperation(Token::Value::ADD, reg).JumpIfFalse(&label4);
|
|
|
|
builder.BinaryOperation(Token::Value::ADD, reg).JumpIfTrue(&label3);
|
|
|
|
builder.CompareOperation(Token::Value::EQ, reg).JumpIfFalse(&label2);
|
|
|
|
builder.CompareOperation(Token::Value::EQ, reg).JumpIfTrue(&label1);
|
2015-09-24 15:20:47 +00:00
|
|
|
builder.Jump(&label0);
|
|
|
|
builder.Return();
|
|
|
|
|
|
|
|
Handle<BytecodeArray> array = builder.ToBytecodeArray();
|
|
|
|
BytecodeArrayIterator iterator(array);
|
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
|
2015-10-01 17:22:58 +00:00
|
|
|
CHECK_EQ(iterator.GetImmediateOperand(0), 0);
|
2015-09-24 15:20:47 +00:00
|
|
|
iterator.Advance();
|
2015-10-30 16:48:18 +00:00
|
|
|
// Ignore compare operation.
|
|
|
|
iterator.Advance();
|
2015-09-24 15:20:47 +00:00
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue);
|
2016-03-21 17:08:21 +00:00
|
|
|
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
|
2015-11-03 11:27:54 +00:00
|
|
|
CHECK_EQ(iterator.GetImmediateOperand(0), -2);
|
2015-09-24 15:20:47 +00:00
|
|
|
iterator.Advance();
|
2015-10-30 16:48:18 +00:00
|
|
|
// Ignore compare operation.
|
|
|
|
iterator.Advance();
|
2015-09-24 15:20:47 +00:00
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse);
|
2016-03-21 17:08:21 +00:00
|
|
|
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
|
2015-11-03 11:27:54 +00:00
|
|
|
CHECK_EQ(iterator.GetImmediateOperand(0), -2);
|
2015-09-24 15:20:47 +00:00
|
|
|
iterator.Advance();
|
2015-10-30 16:48:18 +00:00
|
|
|
// Ignore binary operation.
|
|
|
|
iterator.Advance();
|
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrue);
|
2016-03-21 17:08:21 +00:00
|
|
|
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
|
2015-11-03 11:27:54 +00:00
|
|
|
CHECK_EQ(iterator.GetImmediateOperand(0), -2);
|
2015-10-30 16:48:18 +00:00
|
|
|
iterator.Advance();
|
|
|
|
// Ignore binary operation.
|
|
|
|
iterator.Advance();
|
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanFalse);
|
2016-03-21 17:08:21 +00:00
|
|
|
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
|
2015-11-03 11:27:54 +00:00
|
|
|
CHECK_EQ(iterator.GetImmediateOperand(0), -2);
|
2015-10-30 16:48:18 +00:00
|
|
|
iterator.Advance();
|
2015-11-03 11:27:54 +00:00
|
|
|
for (int i = 0; i < 63; i++) {
|
2015-09-24 15:20:47 +00:00
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
|
2016-03-21 17:08:21 +00:00
|
|
|
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
|
2015-11-03 11:27:54 +00:00
|
|
|
CHECK_EQ(iterator.GetImmediateOperand(0), -i * 2 - 4);
|
2015-09-24 15:20:47 +00:00
|
|
|
iterator.Advance();
|
|
|
|
}
|
2016-03-21 17:08:21 +00:00
|
|
|
// Check padding to force wide backwards jumps.
|
|
|
|
for (int i = 0; i < 256; i++) {
|
2016-05-12 19:18:07 +00:00
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kDebugger);
|
2016-03-21 17:08:21 +00:00
|
|
|
iterator.Advance();
|
|
|
|
}
|
2015-10-30 16:48:18 +00:00
|
|
|
// Ignore binary operation.
|
|
|
|
iterator.Advance();
|
2016-03-21 17:08:21 +00:00
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanFalse);
|
|
|
|
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kDouble);
|
|
|
|
CHECK_EQ(iterator.GetImmediateOperand(0), -389);
|
2015-10-30 16:48:18 +00:00
|
|
|
iterator.Advance();
|
|
|
|
// Ignore binary operation.
|
|
|
|
iterator.Advance();
|
2016-03-21 17:08:21 +00:00
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrue);
|
|
|
|
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kDouble);
|
|
|
|
CHECK_EQ(iterator.GetImmediateOperand(0), -399);
|
2015-10-30 16:48:18 +00:00
|
|
|
iterator.Advance();
|
|
|
|
// Ignore compare operation.
|
|
|
|
iterator.Advance();
|
2016-03-21 17:08:21 +00:00
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse);
|
|
|
|
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kDouble);
|
|
|
|
CHECK_EQ(iterator.GetImmediateOperand(0), -409);
|
2015-10-30 16:48:18 +00:00
|
|
|
iterator.Advance();
|
|
|
|
// Ignore compare operation.
|
2015-09-24 15:20:47 +00:00
|
|
|
iterator.Advance();
|
2016-03-21 17:08:21 +00:00
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue);
|
|
|
|
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kDouble);
|
|
|
|
CHECK_EQ(iterator.GetImmediateOperand(0), -419);
|
2015-09-24 15:20:47 +00:00
|
|
|
iterator.Advance();
|
2016-03-21 17:08:21 +00:00
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
|
|
|
|
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kDouble);
|
|
|
|
CHECK_EQ(iterator.GetImmediateOperand(0), -425);
|
2015-09-24 15:20:47 +00:00
|
|
|
iterator.Advance();
|
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
|
|
|
|
iterator.Advance();
|
|
|
|
CHECK(iterator.done());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TEST_F(BytecodeArrayBuilderTest, LabelReuse) {
|
2016-02-02 14:31:35 +00:00
|
|
|
BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0);
|
2015-09-24 15:20:47 +00:00
|
|
|
|
|
|
|
// Labels can only have 1 forward reference, but
|
|
|
|
// can be referred to mulitple times once bound.
|
|
|
|
BytecodeLabel label;
|
|
|
|
|
|
|
|
builder.Jump(&label).Bind(&label).Jump(&label).Jump(&label).Return();
|
|
|
|
|
|
|
|
Handle<BytecodeArray> array = builder.ToBytecodeArray();
|
|
|
|
BytecodeArrayIterator iterator(array);
|
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
|
2015-10-01 17:22:58 +00:00
|
|
|
CHECK_EQ(iterator.GetImmediateOperand(0), 2);
|
2015-09-24 15:20:47 +00:00
|
|
|
iterator.Advance();
|
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
|
2015-10-01 17:22:58 +00:00
|
|
|
CHECK_EQ(iterator.GetImmediateOperand(0), 0);
|
2015-09-24 15:20:47 +00:00
|
|
|
iterator.Advance();
|
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
|
2015-10-01 17:22:58 +00:00
|
|
|
CHECK_EQ(iterator.GetImmediateOperand(0), -2);
|
2015-09-24 15:20:47 +00:00
|
|
|
iterator.Advance();
|
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
|
|
|
|
iterator.Advance();
|
|
|
|
CHECK(iterator.done());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TEST_F(BytecodeArrayBuilderTest, LabelAddressReuse) {
|
|
|
|
static const int kRepeats = 3;
|
|
|
|
|
2016-02-02 14:31:35 +00:00
|
|
|
BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0);
|
2015-09-24 15:20:47 +00:00
|
|
|
for (int i = 0; i < kRepeats; i++) {
|
|
|
|
BytecodeLabel label;
|
|
|
|
builder.Jump(&label).Bind(&label).Jump(&label).Jump(&label);
|
|
|
|
}
|
|
|
|
builder.Return();
|
|
|
|
|
|
|
|
Handle<BytecodeArray> array = builder.ToBytecodeArray();
|
|
|
|
BytecodeArrayIterator iterator(array);
|
|
|
|
for (int i = 0; i < kRepeats; i++) {
|
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
|
2015-10-01 17:22:58 +00:00
|
|
|
CHECK_EQ(iterator.GetImmediateOperand(0), 2);
|
2015-09-24 15:20:47 +00:00
|
|
|
iterator.Advance();
|
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
|
2015-10-01 17:22:58 +00:00
|
|
|
CHECK_EQ(iterator.GetImmediateOperand(0), 0);
|
2015-09-24 15:20:47 +00:00
|
|
|
iterator.Advance();
|
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
|
2015-10-01 17:22:58 +00:00
|
|
|
CHECK_EQ(iterator.GetImmediateOperand(0), -2);
|
2015-09-24 15:20:47 +00:00
|
|
|
iterator.Advance();
|
|
|
|
}
|
|
|
|
CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
|
|
|
|
iterator.Advance();
|
|
|
|
CHECK(iterator.done());
|
|
|
|
}
|
|
|
|
|
2015-08-13 11:27:54 +00:00
|
|
|
} // namespace interpreter
|
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|