source: webkit/trunk/Source/JavaScriptCore/offlineasm/instructions.rb

Last change on this file was 295449, checked in by [email protected], 3 years ago

Enable WasmLLInt on ARMv7

Patch by Geza Lore <Geza Lore> on 2022-06-10
Patch by Geza Lore <Geza Lore> on 2022-05-27
https://bugs.webkit.org/show_bug.cgi?id=221260

Reviewed by Saam Barati.

Patch by Geza Lore and Xan López.

Implement the LLInt tier of WebAssembly for ARMv7. A lot of the
work will be shared by any 32bit port, but the offlineassembler
has only been updated for ARMv7 so far.

Main highlights:

We have split the WebAssembly.asm file into three chunks,
following what LowLevelInterpreter.asm does. The common code
remains in WebAssembly.asm, and 32 and 64bit specific code (mostly
opcode implementations) goes into WebAssembly32_64.asm and
WebAssembly64.asm.

We have decided to use consecutive even/odd pairs of GPRs for every
type of wasm values, even if they are 32bit (i32/f32), with the odd
(higher) numbered GPR holding the more significant half. 32bit values
are held in the even (lower) numbered register. This makes the code
much simpler and allows us to share more code with the 64bit variant.
This is mostly relevant for argument passing, and given that every
value ends up in the stack anyway we do not think it is significant
from a performance POV.

We are reusing JSValueRegs to hold Wasm values too. Obviously they
are not really JSValues, so it might make sense to create a base
class that can be used for both JS and Wasm values.

We do not have enough registers to keep things like the memory
base pointer and size in pinned registers, so we are forced to
load them on each use.

We disable the 'Signaling' memory mode, since the current
implementation relies on being able to mprotect a 232 + redzone
region of memory. This can be changed in the future but it's not a
priority at the moment.

  • stress/sampling-profiler-wasm-name-section.js:
  • stress/sampling-profiler-wasm.js:
  • wasm/regress/llint-callee-saves-with-fast-memory.js:
  • CMakeLists.txt:
  • assembler/ARMv7Assembler.h:

(JSC::ARMv7Assembler::vcvt_signedToFloatingPoint):

  • assembler/MacroAssemblerARMv7.h:

(JSC::MacroAssemblerARMv7::convertInt32ToFloat):
(JSC::MacroAssemblerARMv7::threadSafePatchableNearCall):
(JSC::MacroAssemblerARMv7::callOperation):

  • b3/B3ValueRep.h:

(JSC::B3::ValueRep::ValueRep):

  • bytecode/BytecodeDumper.cpp:

(JSC::Wasm::BytecodeDumper::formatConstant const):

  • interpreter/CallFrame.h: adapt to new callee tagging format.

(JSC::CallFrame::callee const):
(JSC::CallFrame::unsafeCallee const):

  • interpreter/CalleeBits.h: add wasm tagging of callee values for

32bit.
(JSC::CalleeBits::CalleeBits):
(JSC::CalleeBits::operator=):
(JSC::CalleeBits::boxWasm):
(JSC::CalleeBits::isWasm const):
(JSC::CalleeBits::asWasmCallee const):

  • interpreter/Register.h:

(JSC::Register::unboxedFloat const):
(JSC::Register::asanUnsafeUnboxedFloat const):

  • jit/AssemblyHelpers.h:

(JSC::AssemblyHelpers::unboxDouble):

  • jit/RegisterAtOffsetList.cpp:

(JSC::RegisterAtOffsetList::RegisterAtOffsetList):

  • jit/RegisterAtOffsetList.h:

(JSC::RegisterAtOffsetList::sizeOfAreaInBytes const):

  • jit/RegisterSet.cpp:

(JSC::RegisterSet::macroScratchRegisters):

  • llint/LowLevelInterpreter32_64.asm:
  • llint/WebAssembly.asm:
  • llint/WebAssembly32_64.asm: Added.
  • llint/WebAssembly64.asm: Added.
  • offlineasm/arm.rb:
  • offlineasm/instructions.rb:
  • offlineasm/registers.rb:
  • offlineasm/risc.rb:
  • runtime/JSCJSValue.h:

(JSC::wasmUnboxedFloat):

  • runtime/JSCJSValueInlines.h:

(JSC::JSValue::JSValue):

  • wasm/WasmAirIRGenerator.cpp:

(JSC::Wasm::AirIRGenerator::useSignalingMemory const):
(JSC::Wasm::AirIRGenerator::AirIRGenerator):
(JSC::Wasm::AirIRGenerator::emitCheckAndPreparePointer):
(JSC::Wasm::AirIRGenerator::addCall):

  • wasm/WasmB3IRGenerator.cpp:

(JSC::Wasm::B3IRGenerator::useSignalingMemory const):
(JSC::Wasm::B3IRGenerator::B3IRGenerator):
(JSC::Wasm::B3IRGenerator::addArguments):
(JSC::Wasm::B3IRGenerator::emitCheckAndPreparePointer):
(JSC::Wasm::B3IRGenerator::memoryKind):
(JSC::Wasm::B3IRGenerator::addCall):

  • wasm/WasmBinding.cpp:

(JSC::Wasm::wasmToWasm):

  • wasm/WasmCallee.cpp:

(JSC::Wasm::LLIntCallee::calleeSaveRegisters):

  • wasm/WasmCalleeGroup.cpp:

(JSC::Wasm::CalleeGroup::isSafeToRun):

  • wasm/WasmCallingConvention.cpp:

(JSC::Wasm::jsCallingConvention):
(JSC::Wasm::wasmCallingConvention):

  • wasm/WasmCallingConvention.h:

(JSC::Wasm::CallInformation::computeResultsOffsetList):
(JSC::Wasm::WasmCallingConvention::WasmCallingConvention):
(JSC::Wasm::WasmCallingConvention::marshallLocationImpl const):
(JSC::Wasm::WasmCallingConvention::marshallLocation const):
(JSC::Wasm::JSCallingConvention::JSCallingConvention):
(JSC::Wasm::JSCallingConvention::marshallLocationImpl const):
(JSC::Wasm::JSCallingConvention::marshallLocation const):
(JSC::Wasm::JSCallingConvention::callInformationFor const):

  • wasm/WasmFormat.h:
  • wasm/WasmIndexOrName.cpp:

(JSC::Wasm::IndexOrName::IndexOrName):
(JSC::Wasm::makeString):

  • wasm/WasmIndexOrName.h:

(JSC::Wasm::IndexOrName::IndexOrName):
(JSC::Wasm::IndexOrName::isEmpty const):
(JSC::Wasm::IndexOrName::isIndex const):
(JSC::Wasm::IndexOrName::isName const):
(JSC::Wasm::IndexOrName::index const):
(JSC::Wasm::IndexOrName::name const):
(JSC::Wasm::IndexOrName::nameSection const):

  • wasm/WasmInstance.h:

(JSC::Wasm::Instance::updateCachedMemory):

  • wasm/WasmLLIntGenerator.cpp:

(JSC::Wasm::LLIntGenerator::virtualRegisterForWasmLocal):
(JSC::Wasm::LLIntGenerator::callInformationForCaller):
(JSC::Wasm::LLIntGenerator::callInformationForCallee):
(JSC::Wasm::LLIntGenerator::addArguments):
(JSC::Wasm::LLIntGenerator::addLoop):

  • wasm/WasmLLIntPlan.cpp:

(JSC::Wasm::LLIntPlan::didCompleteCompilation):

  • wasm/WasmMemory.cpp:

(JSC::Wasm::MemoryHandle::~MemoryHandle):
(JSC::Wasm::Memory::tryCreate):
(JSC::Wasm::Memory::growShared):
(JSC::Wasm::Memory::grow):
(JSC::Wasm::Memory::copy):

  • wasm/WasmMemory.h:
  • wasm/WasmMemoryInformation.cpp:

(JSC::Wasm::PinnedRegisterInfo::get):

  • wasm/WasmMemoryInformation.h:

(JSC::Wasm::PinnedRegisterInfo::toSave const):

  • wasm/WasmMemoryMode.cpp:

(JSC::Wasm::makeString):

  • wasm/WasmMemoryMode.h:
  • wasm/WasmOpcodeOrigin.cpp:
  • wasm/WasmOpcodeOrigin.h:
  • wasm/WasmOperations.cpp:

(JSC::Wasm::JSC_DEFINE_JIT_OPERATION):

  • wasm/WasmOperations.h:
  • wasm/WasmPageCount.h:
  • wasm/WasmParser.h:

(JSC::Wasm::Parser<SuccessType>::parseUInt32):
(JSC::Wasm::Parser<SuccessType>::parseUInt64):

  • wasm/WasmSlowPaths.cpp:

(JSC::LLInt::WASM_SLOW_PATH_DECL):
(JSC::LLInt::slow_path_wasm_popcount):
(JSC::LLInt::slow_path_wasm_popcountll):
(JSC::LLInt::slow_path_wasm_i32_div_s):
(JSC::LLInt::slow_path_wasm_i32_div_u):
(JSC::LLInt::slow_path_wasm_i32_rem_s):
(JSC::LLInt::slow_path_wasm_i32_rem_u):
(JSC::LLInt::slow_path_wasm_i64_div_s):
(JSC::LLInt::slow_path_wasm_i64_div_u):
(JSC::LLInt::slow_path_wasm_i64_rem_s):
(JSC::LLInt::slow_path_wasm_i64_rem_u):

  • wasm/WasmSlowPaths.h:
  • wasm/WasmValueLocation.cpp:

(JSC::Wasm::ValueLocation::dump const):
(WTF::printInternal):

  • wasm/WasmValueLocation.h:

(JSC::Wasm::ValueLocation::ValueLocation):
(JSC::Wasm::ValueLocation::isGPR const):
(JSC::Wasm::ValueLocation::isFPR const):
(JSC::Wasm::ValueLocation::isStack const):
(JSC::Wasm::ValueLocation::isStackArgument const):
(JSC::Wasm::ValueLocation::jsr const):
(JSC::Wasm::ValueLocation::fpr const):
(JSC::Wasm::ValueLocation::reg): Deleted.
(JSC::Wasm::ValueLocation::isReg const): Deleted.
(JSC::Wasm::ValueLocation::reg const): Deleted.
(JSC::Wasm::ValueLocation::gpr const): Deleted.

  • wasm/js/JSToWasm.cpp:

(JSC::Wasm::marshallJSResult):
(JSC::Wasm::createJSToWasmWrapper):

  • wasm/js/WasmToJS.cpp:

(JSC::Wasm::wasmToJS):

  • wasm/js/WebAssemblyFunction.cpp:

(JSC::WebAssemblyFunction::previousInstanceOffset const):
(JSC::WebAssemblyFunction::jsCallEntrypointSlow):

  • wasm/js/WebAssemblyGlobalConstructor.cpp:

(JSC::JSC_DEFINE_HOST_FUNCTION):

  • wasm/js/WebAssemblyModuleRecord.cpp:

(JSC::WebAssemblyModuleRecord::initializeExports):

  • wtf/PlatformEnable.h: enable WebAssembly on ARMv7.
  • Scripts/run-jsc-stress-tests: allow to run the wasm tests on

armv7 even without jit support (for now).

Canonical link: https://commits.webkit.org/251455@main

File size: 9.9 KB
Line 
1# Copyright (C) 2011-2020 Apple Inc. All rights reserved.
2#
3# Redistribution and use in source and binary forms, with or without
4# modification, are permitted provided that the following conditions
5# are met:
6# 1. Redistributions of source code must retain the above copyright
7# notice, this list of conditions and the following disclaimer.
8# 2. Redistributions in binary form must reproduce the above copyright
9# notice, this list of conditions and the following disclaimer in the
10# documentation and/or other materials provided with the distribution.
11#
12# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
13# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
14# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
15# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
16# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
17# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
18# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
19# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
20# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
21# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
22# THE POSSIBILITY OF SUCH DAMAGE.
23
24require "config"
25require "set"
26
27# Interesting invariant, which we take advantage of: branching instructions
28# always begin with "b", and no non-branching instructions begin with "b".
29# Terminal instructions are "jmp" and "ret".
30
31MACRO_INSTRUCTIONS =
32 [
33 "emit",
34 "addi",
35 "andi",
36 "andf",
37 "andd",
38 "lshifti",
39 "lshiftp",
40 "lshiftq",
41 "muli",
42 "negi",
43 "negp",
44 "negq",
45 "noti",
46 "ori",
47 "orf",
48 "ord",
49 "orh",
50 "rshifti",
51 "urshifti",
52 "rshiftp",
53 "urshiftp",
54 "rshiftq",
55 "urshiftq",
56 "lrotatei",
57 "lrotateq",
58 "rrotatei",
59 "rrotateq",
60 "subi",
61 "xori",
62 "load2ia",
63 "loadi",
64 "loadis",
65 "loadb",
66 "loadbsi",
67 "loadbsq",
68 "loadh",
69 "loadhsi",
70 "loadhsq",
71 "store2ia",
72 "storei",
73 "storeh",
74 "storeb",
75 "loadf",
76 "loadd",
77 "moved",
78 "storef",
79 "stored",
80 "addf",
81 "addd",
82 "divf",
83 "divd",
84 "subf",
85 "subd",
86 "mulf",
87 "muld",
88 "sqrtf",
89 "sqrtd",
90 "floorf",
91 "floord",
92 "roundf",
93 "roundd",
94 "truncatef",
95 "truncated",
96 "truncatef2i",
97 "truncatef2q",
98 "truncated2q",
99 "truncated2i",
100 "truncatef2is",
101 "truncated2is",
102 "truncatef2qs",
103 "truncated2qs",
104 "ci2d",
105 "ci2ds",
106 "ci2f",
107 "ci2fs",
108 "cq2f",
109 "cq2fs",
110 "cq2d",
111 "cq2ds",
112 "cd2f",
113 "cf2d",
114 "fii2d", # usage: fii2d <gpr with least significant bits>, <gpr with most significant bits>, <fpr>
115 "fd2ii", # usage: fd2ii <fpr>, <gpr with least significant bits>, <gpr with most significant bits>
116 "fq2d",
117 "fd2q",
118 "bdeq",
119 "bdneq",
120 "bdgt",
121 "bdgteq",
122 "bdlt",
123 "bdlteq",
124 "bdequn",
125 "bdnequn",
126 "bdgtun",
127 "bdgtequn",
128 "bdltun",
129 "bdltequn",
130 "bfeq",
131 "bfgt",
132 "bflt",
133 "bfgtun",
134 "bfgtequn",
135 "bfltun",
136 "bfltequn",
137 "btd2i",
138 "td2i",
139 "bcd2i",
140 "movdz",
141 "pop",
142 "push",
143 "move",
144 "sxi2q",
145 "zxi2q",
146 "sxb2i",
147 "sxh2i",
148 "sxb2q",
149 "sxh2q",
150 "nop",
151 "bieq",
152 "bineq",
153 "bia",
154 "biaeq",
155 "bib",
156 "bibeq",
157 "bigt",
158 "bigteq",
159 "bilt",
160 "bilteq",
161 "bbeq",
162 "bbneq",
163 "bba",
164 "bbaeq",
165 "bbb",
166 "bbbeq",
167 "bbgt",
168 "bbgteq",
169 "bblt",
170 "bblteq",
171 "btis",
172 "btiz",
173 "btinz",
174 "btbs",
175 "btbz",
176 "btbnz",
177 "jmp",
178 "baddio",
179 "baddis",
180 "baddiz",
181 "baddinz",
182 "bsubio",
183 "bsubis",
184 "bsubiz",
185 "bsubinz",
186 "bmulio",
187 "bmulis",
188 "bmuliz",
189 "bmulinz",
190 "borio",
191 "boris",
192 "boriz",
193 "borinz",
194 "break",
195 "call",
196 "ret",
197 "cbeq",
198 "cbneq",
199 "cba",
200 "cbaeq",
201 "cbb",
202 "cbbeq",
203 "cbgt",
204 "cbgteq",
205 "cblt",
206 "cblteq",
207 "cieq",
208 "cineq",
209 "cia",
210 "ciaeq",
211 "cib",
212 "cibeq",
213 "cigt",
214 "cigteq",
215 "cilt",
216 "cilteq",
217 "tis",
218 "tiz",
219 "tinz",
220 "tbs",
221 "tbz",
222 "tbnz",
223 "tps",
224 "tpz",
225 "tpnz",
226 "peek",
227 "poke",
228 "bpeq",
229 "bpneq",
230 "bpa",
231 "bpaeq",
232 "bpb",
233 "bpbeq",
234 "bpgt",
235 "bpgteq",
236 "bplt",
237 "bplteq",
238 "addp",
239 "mulp",
240 "andp",
241 "orp",
242 "subp",
243 "xorp",
244 "loadp",
245 "cpeq",
246 "cpneq",
247 "cpa",
248 "cpaeq",
249 "cpb",
250 "cpbeq",
251 "cpgt",
252 "cpgteq",
253 "cplt",
254 "cplteq",
255 "storep",
256 "btps",
257 "btpz",
258 "btpnz",
259 "baddpo",
260 "baddps",
261 "baddpz",
262 "baddpnz",
263 "tqs",
264 "tqz",
265 "tqnz",
266 "bqeq",
267 "bqneq",
268 "bqa",
269 "bqaeq",
270 "bqb",
271 "bqbeq",
272 "bqgt",
273 "bqgteq",
274 "bqlt",
275 "bqlteq",
276 "addq",
277 "mulq",
278 "andq",
279 "orq",
280 "subq",
281 "xorq",
282 "loadq",
283 "cqeq",
284 "cqneq",
285 "cqa",
286 "cqaeq",
287 "cqb",
288 "cqbeq",
289 "cqgt",
290 "cqgteq",
291 "cqlt",
292 "cqlteq",
293 "storeq",
294 "btqs",
295 "btqz",
296 "btqnz",
297 "baddqo",
298 "baddqs",
299 "baddqz",
300 "baddqnz",
301 "bo",
302 "bs",
303 "bz",
304 "bnz",
305 "leai",
306 "leap",
307 "memfence",
308 "tagCodePtr",
309 "tagReturnAddress",
310 "untagReturnAddress",
311 "removeCodePtrTag",
312 "untagArrayPtr",
313 "removeArrayPtrTag",
314 "tzcnti",
315 "tzcntq",
316 "lzcnti",
317 "lzcntq",
318 "absf",
319 "absd",
320 "negf",
321 "negd",
322 "ceilf",
323 "ceild",
324 "cfeq",
325 "cdeq",
326 "cfneq",
327 "cfnequn",
328 "cdneq",
329 "cdnequn",
330 "cflt",
331 "cdlt",
332 "cflteq",
333 "cdlteq",
334 "cfgt",
335 "cdgt",
336 "cfgteq",
337 "cdgteq",
338 "fi2f",
339 "ff2i",
340 "tls_loadp",
341 "tls_storep",
342 ]
343
344X86_INSTRUCTIONS =
345 [
346 "cdqi",
347 "idivi",
348 "udivi",
349 "cqoq",
350 "idivq",
351 "udivq",
352 "notq",
353 "atomicxchgaddb",
354 "atomicxchgaddh",
355 "atomicxchgaddi",
356 "atomicxchgaddq",
357 "atomicxchgsubb",
358 "atomicxchgsubh",
359 "atomicxchgsubi",
360 "atomicxchgsubq",
361 "atomicxchgb",
362 "atomicxchgh",
363 "atomicxchgi",
364 "atomicxchgq",
365 "batomicweakcasb",
366 "batomicweakcash",
367 "batomicweakcasi",
368 "batomicweakcasq",
369 "atomicweakcasb",
370 "atomicweakcash",
371 "atomicweakcasi",
372 "atomicweakcasq",
373 "atomicloadb",
374 "atomicloadh",
375 "atomicloadi",
376 "atomicloadq",
377 "fence",
378 ]
379
380ARM_INSTRUCTIONS =
381 [
382 "adci",
383 "bcs",
384 "clrbp",
385 "mvlbl",
386 "globaladdr",
387 "sbci",
388 "moveii",
389 "loadlinkb",
390 "loadlinkh",
391 "loadlinki",
392 "loadlink2i",
393 "storecondb",
394 "storecondh",
395 "storecondi",
396 "storecond2i",
397 ]
398
399ARM64_INSTRUCTIONS =
400 [
401 "bfiq", # Bit field insert <source reg> <last bit written> <width immediate> <dest reg>
402 "pcrtoaddr", # Address from PC relative offset - adr instruction
403 "globaladdr",
404 "notq",
405 "loadlinkacqb",
406 "loadlinkacqh",
407 "loadlinkacqi",
408 "loadlinkacqq",
409 "storecondrelb",
410 "storecondrelh",
411 "storecondreli",
412 "storecondrelq",
413 "fence",
414 # They are available only if Atomic LSE is supported.
415 "atomicxchgaddb",
416 "atomicxchgaddh",
417 "atomicxchgaddi",
418 "atomicxchgaddq",
419 "atomicxchgclearb",
420 "atomicxchgclearh",
421 "atomicxchgcleari",
422 "atomicxchgclearq",
423 "atomicxchgorb",
424 "atomicxchgorh",
425 "atomicxchgori",
426 "atomicxchgorq",
427 "atomicxchgxorb",
428 "atomicxchgxorh",
429 "atomicxchgxori",
430 "atomicxchgxorq",
431 "atomicxchgb",
432 "atomicxchgh",
433 "atomicxchgi",
434 "atomicxchgq",
435 "atomicweakcasb",
436 "atomicweakcash",
437 "atomicweakcasi",
438 "atomicweakcasq",
439 "atomicloadb",
440 "atomicloadh",
441 "atomicloadi",
442 "atomicloadq",
443 ]
444
445RISC_INSTRUCTIONS =
446 [
447 "smulli", # Multiply two 32-bit words and produce a 64-bit word
448 "umulli", # Multiply two 32-bit words and produce a 64-bit word
449 "addis", # Add integers and set a flag.
450 "subis", # Same, but for subtraction.
451 "oris", # Same, but for bitwise or.
452 "addps", # addis but for pointers.
453 "divi",
454 "divis",
455 "divq",
456 "divqs",
457 "remi",
458 "remis",
459 "remq",
460 "remqs"
461 ]
462
463MIPS_INSTRUCTIONS =
464 [
465 "la",
466 "movz",
467 "movn",
468 "setcallreg",
469 "slt",
470 "sltu",
471 "pichdr"
472 ]
473
474CXX_INSTRUCTIONS =
475 [
476 "cloopCrash", # no operands
477 "cloopCallJSFunction", # operands: callee
478 "cloopCallNative", # operands: callee
479 "cloopCallSlowPath", # operands: callTarget, currentFrame, currentPC
480 "cloopCallSlowPathVoid", # operands: callTarget, currentFrame, currentPC
481 "cloopCallSlowPath3", # operands: callTarget, a0, a1, a2
482 "cloopCallSlowPath4", # operands: callTarget, a0, a1, a2, a3
483
484 # For debugging only:
485 # Takes no operands but simply emits whatever follows in // comments as
486 # a line of C++ code in the generated LLIntAssembly.h file. This can be
487 # used to insert instrumentation into the interpreter loop to inspect
488 # variables of interest. Do not leave these instructions in production
489 # code.
490 "cloopDo", # no operands
491 ]
492
493INSTRUCTIONS = MACRO_INSTRUCTIONS + X86_INSTRUCTIONS + ARM_INSTRUCTIONS + ARM64_INSTRUCTIONS + RISC_INSTRUCTIONS + MIPS_INSTRUCTIONS + CXX_INSTRUCTIONS
494
495INSTRUCTION_SET = INSTRUCTIONS.to_set
496
497def isBranch(instruction)
498 instruction =~ /^b/
499end
500
501def hasFallThrough(instruction)
502 instruction != "ret" and instruction != "jmp"
503end
504
505def isPowerOfTwo(value)
506 return false if value <= 0
507 (value & (value - 1)).zero?
508end
Note: See TracBrowser for help on using the repository browser.